vercel/turborepo · warning
Git download failed: ${formatError(gitError)} Falling back t
Error message
Git download failed:
${formatError(gitError)}
Falling back to downloading the example via tarball. What it means
downloadAndExtractExample() first tries the fast path: a blobless, sparse, shallow `git clone` of vercel/turborepo followed by `sparse-checkout set examples/<name>` and `checkout`. Any failure in that chain (runGit wraps execFileSync and throws `\`git <subcommand>\` failed`) is caught here, warned about, and the code falls back to streaming the codeload.github.com tarball. The message is informational: it names the git error and states the fallback; only if the tarball download also fails does the operation actually throw.
Source
Thrown at packages/turbo-utils/src/examples.ts:573
"--no-checkout",
"--depth",
"1",
"--sparse",
"https://github.com/vercel/turborepo.git",
tempDir
]);
// Set up sparse checkout for just the example we want
runGit(["sparse-checkout", "set", `examples/${name}`], tempDir);
// Checkout the files
runGit(["checkout"], tempDir);
// Copy the example files to the root
const examplePath = join(tempDir, "examples", name);
cpSync(examplePath, normalizedRoot, { recursive: true });
} catch (gitError) {
warn(
`Git download failed:\n${formatError(gitError)}\n` +
"Falling back to downloading the example via tarball."
);
cleanupCloneDirectory(tempDir);
await streamingExtract({
url: "https://codeload.github.com/vercel/turborepo/tar.gz/main",
root: normalizedRoot,
strip: 3,
filter: (p: string, rootPath: string | null) => {
return p.startsWith(`${rootPath}/examples/${name}/`);
}
});
return;
}
// Clean up the temp directory on successView on GitHub (pinned to f9245100cf)
Solutions
- Treat it as benign if the tarball fallback completes — the example is fetched either way; verify the generated files exist.
- Install or upgrade git: `apt-get update && apt-get install -y git` (Debian/alpine: `apk add git`), or on macOS `brew install git`; ensure git >= 2.25 for `sparse-checkout set`.
- If behind a proxy, configure git explicitly: `git config --global http.proxy $HTTPS_PROXY` (git ignores undici's ProxyAgent path), or allow egress to github.com and objects.githubusercontent.com.
- Remove a stale `.turbo-clone-temp` directory in the target root if a previous run was killed mid-clone, then re-run create-turbo.
- If both paths fail, debug the tarball URL directly: `curl -fL https://codeload.github.com/vercel/turborepo/tar.gz/main -o /dev/null` to confirm egress.
Example fix
# before: minimal image, git missing -> 'Git download failed' warning FROM node:22-slim RUN npx create-turbo@latest # after: git present, fast path succeeds FROM node:22-slim RUN apt-get update && apt-get install -y git && rm -rf /var/lib/apt/lists/* RUN npx create-turbo@latest
Defensive patterns
Strategy: validation
Validate before calling
import { execFileSync } from "node:child_process";
function gitFastPathAvailable(): boolean {
try {
const out = execFileSync("git", ["--version"], { stdio: ["pipe", "pipe", "pipe"] }).toString();
const m = out.match(/(\d+)\.(\d+)/); // needs >= 2.25 for `sparse-checkout set`
return !!m && (+m[1] > 2 || (+m[1] === 2 && +m[2] >= 25));
} catch {
return false; // git missing -> expect the warning, tarball fallback will be used
}
} Try / catch
// downloadAndExtractExample already catches internally and falls back to the tarball;
// only the fallback itself can throw, so wrap the call and retry on network errors:
try {
await downloadAndExtractExample(root, exampleName);
} catch (err) {
if (err instanceof Error && /ENOTFOUND|ETIMEDOUT|ECONNRESET|fetch failed/.test(err.message)) {
await downloadAndExtractExample(root, exampleName); // one retry for transient egress failure
} else {
throw err;
}
} Prevention
- Install git (>= 2.25) in Docker/CI images where you run create-turbo to keep the fast path available.
- When behind a corporate proxy, set git's own config (git config --global http.proxy ...) — the library's undici ProxyAgent does not apply to the git subprocess.
- Clean up .turbo-clone-temp in the target directory if a previous scaffold was interrupted.
- Read the warning as 'degraded, not failed': confirm the example files landed before investigating the git error.
When it happens
Trigger: execFileSync('git', ...) fails for any of: git not installed (ENOENT), git older than 2.25 (no `sparse-checkout set`; partial clone `--filter=blob:none` needs >= 2.19), network egress to github.com blocked by a corporate firewall/proxy (git does not honor https_proxy the way undici does here), TLS/credential helper misconfiguration, or a leftover conflict-marked .turbo-clone-temp directory making cpSync fail — e.g. running `create-turbo --example <name>` on a minimal Docker image or locked-down CI runner.
Common situations: `node:<slim>`/alpine Docker images without the git package; CI runners behind an egress proxy that allows HTTPS fetch (so the tarball fallback works) but blocks git's smart HTTP or DNS; ancient git from a distro repo; flaky networks where the clone times out. Users usually see this warning and the scaffold still succeeds via the tarball.
Related errors
- `git ${args[0]}` failed: ${formatError(error)}
- Directory path contains potentially unsafe characters: ${dir
- Failed to download: ${response.status}
- Invalid ${description}: path must be an absolute, non-empty
- isErrorLike(reason) ? reason.message : String(reason)
AI-assisted analysis of vercel/turborepo@f9245100cf (2026-08-17).
Data as JSON: /api/errors/c7a85eea85a375ff.
Report an issue: GitHub.