diff --git a/.changeset/friendly-birds-boil.md b/.changeset/friendly-birds-boil.md new file mode 100644 index 0000000000..220c909889 --- /dev/null +++ b/.changeset/friendly-birds-boil.md @@ -0,0 +1,5 @@ +--- +"create-t3-app": patch +--- + +added explicit error handling for the specified issue diff --git a/.changeset/weak-cats-tease.md b/.changeset/weak-cats-tease.md new file mode 100644 index 0000000000..968772a241 --- /dev/null +++ b/.changeset/weak-cats-tease.md @@ -0,0 +1,5 @@ +--- +"create-t3-app": patch +--- + +Improve error handling for git dubious ownership errors. Now provides clear explanations and exact fix commands when git operations fail due to dubious ownership on FAT32/exFAT/network drives. diff --git a/cli/src/helpers/git.ts b/cli/src/helpers/git.ts index 95871067c4..201aaed427 100644 --- a/cli/src/helpers/git.ts +++ b/cli/src/helpers/git.ts @@ -31,7 +31,17 @@ export const isInsideGitRepo = async (dir: string): Promise => { stdout: "ignore", }); return true; - } catch { + } catch (error) { + // Check for dubious ownership error and warn the user + const errorMessage = error instanceof Error ? error.message : String(error); + if (errorMessage.includes("dubious ownership")) { + logger.warn( + `Git detected dubious ownership in repository at '${dir}'.\n` + + `This occurs on file systems that don't record ownership (FAT32, exFAT, network drives).\n` + + `Common on external drives, USB drives, and Windows network shares.\n\n` + + `To fix this, run: ${chalk.cyan(`git config --global --add safe.directory "${dir}"`)}\n` + ); + } // Else, it will throw a git-error and we return false return false; } @@ -125,12 +135,27 @@ export const initializeGit = async (projectDir: string) => { "git" )}\n` ); - } catch { - // Safeguard, should be unreachable - spinner.fail( - `${chalk.bold.red( - "Failed:" - )} could not initialize git. Update git to the latest version!\n` - ); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + + // Check for dubious ownership error and provide helpful guidance + if (errorMessage.includes("dubious ownership")) { + spinner.fail( + `${chalk.bold.red("Failed:")} Git detected dubious ownership in repository.\n\n` + + `${chalk.yellow("Cause:")} The file system doesn't record ownership (FAT32, exFAT, network drive).\n` + + `${chalk.dim("This is common on external drives, USB drives, and Windows network shares.")}\n\n` + + `${chalk.bold("To fix this, run:")}\n` + + ` ${chalk.cyan(`git config --global --add safe.directory "${projectDir}"`)}\n\n` + + `${chalk.dim("Or to trust all repositories:")}\n` + + ` ${chalk.cyan("git config --global --add safe.directory '*'")}\n` + ); + } else { + // Show the actual error message instead of generic text + spinner.fail( + `${chalk.bold.red("Failed:")} could not initialize git.\n` + + `${chalk.yellow("Error:")} ${errorMessage}\n` + + `${chalk.dim("Make sure git is updated to the latest version.")}\n` + ); + } } }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 1a7ca111c2..03a25757ea 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -196,37 +196,6 @@ importers: specifier: ^3.24.2 version: 3.24.2 - cli/template/base: - dependencies: - '@t3-oss/env-nextjs': - specifier: ^0.12.0 - version: 0.12.0(typescript@5.9.3)(zod@3.25.76) - next: - specifier: ^15.5.9 - version: 15.5.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: - specifier: ^19.2.3 - version: 19.2.3 - react-dom: - specifier: ^19.2.3 - version: 19.2.3(react@19.2.3) - zod: - specifier: ^3.24.2 - version: 3.25.76 - devDependencies: - '@types/node': - specifier: ^24.10.1 - version: 24.10.3 - '@types/react': - specifier: ~19.1.0 - version: 19.1.17 - '@types/react-dom': - specifier: ~19.1.0 - version: 19.1.11(@types/react@19.1.17) - typescript: - specifier: ^5.8.2 - version: 5.9.3 - www: dependencies: '@algolia/client-search': @@ -2293,9 +2262,6 @@ packages: '@types/node@24.10.1': resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==} - '@types/node@24.10.3': - resolution: {integrity: sha512-gqkrWUsS8hcm0r44yn7/xZeV1ERva/nLgrLxFRUGb7aoNMIJfZJ3AC261zDQuOAKC7MiXai1WCpYc48jAHoShQ==} - '@types/normalize-package-data@2.4.1': resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} @@ -4173,7 +4139,6 @@ packages: libsql@0.4.7: resolution: {integrity: sha512-T9eIRCs6b0J1SHKYIvD8+KCJMcWZ900iZyxdnSCdqxN12Z1ijzT+jY5nrk72Jw4B0HGzms2NgpryArlJqvc3Lw==} - cpu: [x64, arm64, wasm32] os: [darwin, linux, win32] lightningcss-darwin-arm64@1.29.2: @@ -5945,11 +5910,6 @@ packages: engines: {node: '>=14.17'} hasBin: true - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - ufo@1.5.4: resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} @@ -6454,9 +6414,6 @@ packages: zod@3.24.2: resolution: {integrity: sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==} - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -8189,11 +8146,6 @@ snapshots: typescript: 5.8.2 zod: 3.24.2 - '@t3-oss/env-core@0.12.0(typescript@5.9.3)(zod@3.25.76)': - optionalDependencies: - typescript: 5.9.3 - zod: 3.25.76 - '@t3-oss/env-nextjs@0.12.0(typescript@5.8.2)(zod@3.24.2)': dependencies: '@t3-oss/env-core': 0.12.0(typescript@5.8.2)(zod@3.24.2) @@ -8201,13 +8153,6 @@ snapshots: typescript: 5.8.2 zod: 3.24.2 - '@t3-oss/env-nextjs@0.12.0(typescript@5.9.3)(zod@3.25.76)': - dependencies: - '@t3-oss/env-core': 0.12.0(typescript@5.9.3)(zod@3.25.76) - optionalDependencies: - typescript: 5.9.3 - zod: 3.25.76 - '@tailwindcss/node@4.0.15': dependencies: enhanced-resolve: 5.18.1 @@ -8406,10 +8351,6 @@ snapshots: dependencies: undici-types: 7.16.0 - '@types/node@24.10.3': - dependencies: - undici-types: 7.16.0 - '@types/normalize-package-data@2.4.1': {} '@types/react-dom@19.1.11(@types/react@19.1.17)': @@ -11322,29 +11263,6 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@15.5.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3): - dependencies: - '@next/env': 15.5.9 - '@swc/helpers': 0.5.15 - caniuse-lite: 1.0.30001760 - postcss: 8.4.31 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - styled-jsx: 5.1.6(react@19.2.3) - optionalDependencies: - '@next/swc-darwin-arm64': 15.5.7 - '@next/swc-darwin-x64': 15.5.7 - '@next/swc-linux-arm64-gnu': 15.5.7 - '@next/swc-linux-arm64-musl': 15.5.7 - '@next/swc-linux-x64-gnu': 15.5.7 - '@next/swc-linux-x64-musl': 15.5.7 - '@next/swc-win32-arm64-msvc': 15.5.7 - '@next/swc-win32-x64-msvc': 15.5.7 - sharp: 0.34.5 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - nlcst-to-string@4.0.0: dependencies: '@types/nlcst': 2.0.3 @@ -12546,11 +12464,6 @@ snapshots: optionalDependencies: '@babel/core': 7.26.10 - styled-jsx@5.1.6(react@19.2.3): - dependencies: - client-only: 0.0.1 - react: 19.2.3 - sucrase@3.35.0: dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -12822,8 +12735,6 @@ snapshots: typescript@5.8.2: {} - typescript@5.9.3: {} - ufo@1.5.4: {} ultrahtml@1.5.3: {} @@ -13302,6 +13213,4 @@ snapshots: zod@3.24.2: {} - zod@3.25.76: {} - zwitch@2.0.4: {} diff --git a/test-dubious-ownership.js b/test-dubious-ownership.js new file mode 100644 index 0000000000..1823fb311e --- /dev/null +++ b/test-dubious-ownership.js @@ -0,0 +1,99 @@ +/** + * Test script to reproduce the "dubious ownership" error bug + * + * This simulates what happens when Git throws a "dubious ownership" error + * on Windows drives (F:/, E:/) or network shares. + */ + +console.log("šŸ” REPRODUCING THE BUG\n"); +console.log("=".repeat(60)); + +// Simulate the current buggy code +async function testBuggyVersion() { + console.log("\nāŒ CURRENT BUGGY BEHAVIOR:"); + console.log("-".repeat(60)); + + try { + // This simulates what happens when git throws dubious ownership error + throw new Error(`Command failed with exit code 128: git init +fatal: detected dubious ownership in repository at 'F:/test/ct3a' +'F:/test/ct3a' is on a file system that does not record ownership +To add an exception for this directory, call: + + git config --global --add safe.directory F:/test/ct3a`); + } catch { + // THIS IS THE BUG - catches error but doesn't look at it! + console.log( + "āŒ Failed: could not initialize git. Update git to the latest version!", + ); + console.log(" ↑ USELESS MESSAGE - doesn't tell user the real problem!\n"); + } +} + +// Proposed fixed version +async function testFixedVersion() { + console.log("\nāœ… PROPOSED FIX:"); + console.log("-".repeat(60)); + + try { + // This simulates what happens when git throws dubious ownership error + throw new Error(`Command failed with exit code 128: git init +fatal: detected dubious ownership in repository at 'F:/test/ct3a' +'F:/test/ct3a' is on a file system that does not record ownership +To add an exception for this directory, call: + + git config --global --add safe.directory F:/test/ct3a`); + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + + if (errorMessage.includes("dubious ownership")) { + console.log("āŒ Failed: Git detected dubious ownership in repository.\n"); + console.log( + "Cause: The file system doesn't record ownership (FAT32, exFAT, network drive).", + ); + console.log( + "This is common on external drives, USB drives, and Windows network shares.\n", + ); + console.log("To fix this, run:"); + console.log( + ' git config --global --add safe.directory "F:/test/ct3a"\n', + ); + console.log("Or to trust all repositories:"); + console.log(" git config --global --add safe.directory '*'\n"); + console.log( + " ↑ HELPFUL MESSAGE - clearly explains FAT32/exFAT ownership issue!", + ); + } else { + console.log(`āŒ Failed: could not initialize git.`); + console.log(`Error: ${errorMessage}`); + } + } +} + +// Show where in the code this happens +console.log("\nšŸ“ WHERE THE BUG IS IN THE CODE:"); +console.log("-".repeat(60)); +console.log("File: cli/src/helpers/git.ts"); +console.log("\nšŸ› Line 26-38 - isInsideGitRepo() function:"); +console.log(` + } catch { // āŒ Ignores error silently + return false; + } +`); + +console.log("\nšŸ› Line 127-136 - initializeGit() function:"); +console.log(` + } catch { // āŒ Catches error but doesn't examine it! + spinner.fail( + "Failed: could not initialize git. Update git to the latest version!" + ); + } +`); + +console.log("\n" + "=".repeat(60)); +console.log("DEMONSTRATION:\n"); + +await testBuggyVersion(); +await testFixedVersion(); + +console.log("=".repeat(60));