vercel/turborepo · error · Error
Failed to download: ${response.status}
Error message
Failed to download: ${response.status} What it means
streamingExtract() in @turbo/utils fetches a tarball URL (used as the fallback path of downloadAndExtractExample, fetching https://codeload.github.com/vercel/turborepo/tar.gz/main) and throws with the HTTP status when the response is not ok or has no body. This path is reached when the primary git clone strategy fails.
Source
Thrown at packages/turbo-utils/src/examples.ts:346
controller.abort();
}, DOWNLOAD_TIMEOUT);
// Track all write streams so we can clean them up on abort/error
const writeStreams: Array<Writable> = [];
// Pre-resolve root once for performance (avoids calling resolve() per entry)
const resolvedRoot = resolve(root);
// Cache created directories to avoid redundant mkdirSync calls
const createdDirs = new Set<string>();
try {
const response = await fetch(url, {
...buildFetchInit(url),
signal: controller.signal
});
if (!response.ok || !response.body) {
throw new Error(`Failed to download: ${response.status}`);
}
const body = Readable.fromWeb(response.body as ReadableStream);
let rootPath: string | null = null;
// Track all file write operations so we can wait for them to complete
const fileWritePromises: Array<Promise<void>> = [];
const parser = new Parser({
filter: (p: string) => {
// Determine the unpacked root path dynamically instead of hardcoding.
// This avoids issues when the repository has been renamed.
if (rootPath === null) {
const pathSegments = p.split("/");
rootPath = pathSegments.length ? pathSegments[0] : null;
}
return filter(p, rootPath);
},View on GitHub (pinned to 9f94a7d215)
Solutions
- Wait and retry if the status is 429/403/5xx — GitHub rate limits are transient
- Check connectivity: curl -I https://codeload.github.com/vercel/turborepo/tar.gz/main
- Install git so the primary clone path succeeds and the tarball fallback is not needed
- Authenticate or use a personal access token / different network if rate limiting persists
Defensive patterns
Strategy: retry
Validate before calling
const ok = await fetch(url, { method: "HEAD" }).then((r) => r.ok).catch(() => false);
if (!ok) {
// skip extraction, warn user, or switch to a mirror
} Type guard
function isDownloadStatusError(e: unknown): boolean {
return e instanceof Error && /^Failed to download: \d{3}$/.test(e.message);
} Try / catch
for (const delay of [1000, 5000, 15000]) {
try {
await streamingExtract({ url, root, strip, filter });
break;
} catch (e) {
if (e instanceof Error && e.message.startsWith("Failed to download:")) {
await new Promise((r) => setTimeout(r, delay));
continue;
}
throw e;
}
} Prevention
- Ensure git is installed so the tarball fallback path is rarely used
- Cache or mirror the tarball for CI runs to avoid GitHub rate limits
- Treat 429/5xx as transient but 404 as permanent — branch on the embedded status
When it happens
Trigger: An HTTP >= 400 from codeload.github.com for the turborepo main tarball: 429/403 GitHub rate limiting, 5xx outages, or 404 if the branch name changes; also a 200 response with an empty body (response.body null), which some proxies produce.
Common situations: GitHub API/tarball rate limits hit from shared CI runners; environments where git is missing so the clone path always falls back to tarball; network appliances mangling streamed responses.
Related errors
- isErrorLike(reason) ? reason.message : String(reason)
- Unable to fetch the latest version of ${packageName}
- `git ${args[0]}` failed: ${formatError(error)}
AI-assisted analysis of vercel/turborepo@9f94a7d215 (2026-08-16).
Data as JSON: /api/errors/e05a70d80838298b.
Report an issue: GitHub.