{"record":{"id":"e05a70d80838298b","repo":"vercel/turborepo","slug":"failed-to-download-response-status","errorCode":null,"errorMessage":"Failed to download: ${response.status}","messagePattern":"Failed to download: (.+?)","errorType":"http","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/turbo-utils/src/examples.ts","lineNumber":346,"sourceCode":"    controller.abort();\n  }, DOWNLOAD_TIMEOUT);\n\n  // Track all write streams so we can clean them up on abort/error\n  const writeStreams: Array<Writable> = [];\n\n  // Pre-resolve root once for performance (avoids calling resolve() per entry)\n  const resolvedRoot = resolve(root);\n\n  // Cache created directories to avoid redundant mkdirSync calls\n  const createdDirs = new Set<string>();\n\n  try {\n    const response = await fetch(url, {\n      ...buildFetchInit(url),\n      signal: controller.signal\n    });\n    if (!response.ok || !response.body) {\n      throw new Error(`Failed to download: ${response.status}`);\n    }\n\n    const body = Readable.fromWeb(response.body as ReadableStream);\n    let rootPath: string | null = null;\n\n    // Track all file write operations so we can wait for them to complete\n    const fileWritePromises: Array<Promise<void>> = [];\n\n    const parser = new Parser({\n      filter: (p: string) => {\n        // Determine the unpacked root path dynamically instead of hardcoding.\n        // This avoids issues when the repository has been renamed.\n        if (rootPath === null) {\n          const pathSegments = p.split(\"/\");\n          rootPath = pathSegments.length ? pathSegments[0] : null;\n        }\n        return filter(p, rootPath);\n      },","sourceCodeStart":328,"sourceCodeEnd":364,"githubUrl":"https://github.com/vercel/turborepo/blob/9f94a7d215b3881942527dd526afa3fc650869d5/packages/turbo-utils/src/examples.ts#L328-L364","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"const ok = await fetch(url, { method: \"HEAD\" }).then((r) => r.ok).catch(() => false);\nif (!ok) {\n  // skip extraction, warn user, or switch to a mirror\n}","typeGuard":"function isDownloadStatusError(e: unknown): boolean {\n  return e instanceof Error && /^Failed to download: \\d{3}$/.test(e.message);\n}","tryCatchPattern":"for (const delay of [1000, 5000, 15000]) {\n  try {\n    await streamingExtract({ url, root, strip, filter });\n    break;\n  } catch (e) {\n    if (e instanceof Error && e.message.startsWith(\"Failed to download:\")) {\n      await new Promise((r) => setTimeout(r, delay));\n      continue;\n    }\n    throw e;\n  }\n}","preventionTips":["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"],"tags":["network","http-status","download","github"],"backgroundTag":"http-download-failed","analyzedSha":"9f94a7d215b3881942527dd526afa3fc650869d5","analyzedAt":"2026-08-16T19:47:29.531Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}