{"record":{"id":"5e141d344ea2642a","repo":"can1357/oh-my-pi","slug":"failed-to-download-response-status","errorCode":null,"errorMessage":"Failed to download: ${response.status}","messagePattern":"Failed to download: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/utils/tools-manager.ts","lineNumber":204,"sourceCode":"\n\tif (!response.ok) {\n\t\tthrow new Error(`GitHub API error: ${response.status}`);\n\t}\n\n\tconst data = (await response.json()) as { tag_name: string };\n\treturn data.tag_name.replace(/^v/, \"\");\n}\n\n/** Download a tool asset without handing the streaming Response to Bun.write. */\nexport async function downloadFile(url: string, dest: string, signal?: AbortSignal): Promise<void> {\n\tconst downloadSignal = ptree.combineSignals(signal, TOOL_DOWNLOAD_TIMEOUT_MS);\n\tlet response: Response;\n\ttry {\n\t\tresponse = await fetch(url, {\n\t\t\tsignal: downloadSignal,\n\t\t});\n\t\tif (!response.ok) {\n\t\t\tthrow new Error(`Failed to download: ${response.status}`);\n\t\t} else if (!response.body) {\n\t\t\tthrow new Error(\"No response body\");\n\t\t}\n\t\tawait writeResponseBody(dest, response.body, downloadSignal);\n\t} catch (err) {\n\t\tif (isAbortLikeError(err)) {\n\t\t\tthrow new Error(`Download timed out: ${url}`);\n\t\t}\n\t\tthrow err;\n\t}\n}\n\n// Download and install a tool\nasync function downloadTool(tool: ToolName, signal?: AbortSignal): Promise<string> {\n\tconst config = TOOLS[tool];\n\tif (!config) throw new Error(`Unknown tool: ${tool}`);\n\n\tconst plat = os.platform();","sourceCodeStart":186,"sourceCodeEnd":222,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/utils/tools-manager.ts#L186-L222","documentation":"downloadFile() fetches the release asset URL and validates response.ok before streaming the body to disk. Any non-2xx download response (asset removed, bad URL, redirect failure) is rejected with this error, which includes the HTTP status code to identify the cause.","triggerScenarios":"downloadTool fetches the constructed release asset URL https://github.com/<repo>/releases/download/<tagPrefix><version>/<assetName> and GitHub responds with a non-OK status — typically 404 when the asset name for the current version/platform does not exist, or 403/5xx from GitHub-side issues.","commonSituations":"Upstream release renamed or dropped the asset for your OS/arch, a brand-new release where assets are still uploading, tagPrefix mismatch producing a malformed URL, or GitHub returning 403 on throttled direct downloads.","solutions":["Check the status: 404 → the asset URL is wrong or the asset was removed for this release; 403 → throttling; 5xx → transient.","Construct the asset URL and open it in a browser to confirm the asset exists for that version.","If a fresh release has missing assets, retry later once the maintainer finishes uploading, or pin to an earlier complete release.","Verify the getAssetName logic / platform mapping matches the upstream naming scheme for the failing platform.","Retry the download; transient 5xx usually resolves."],"exampleFix":"// before: const binaryPath = await toolsManager.download(\"sg\") // throws \"Failed to download: 404\" | // after: catch, and if /Failed to download: 404/ matches, fall back to system-installed binary; rethrow otherwise","handlingStrategy":"fallback","validationCode":"// verify the asset URL exists before invoking the download path | const head = await fetch(assetUrl, { method: \"HEAD\" }); if (!head.ok) throw new Error(`Asset missing: ${assetUrl} (${head.status})`);","typeGuard":"function isDownloadHttpError(err: unknown): err is Error { return err instanceof Error && /^Failed to download: \\d+$/.test(err.message); }","tryCatchPattern":"try { const p = await toolsManager.path(\"fd\"); } catch (err) { if (isDownloadHttpError(err) && err.message.endsWith(\"404\")) { /* fall back to system-installed binary */ } else throw err; }","preventionTips":["Keep the manager's asset-name mapping in sync with upstream release naming.","Prefer an existing system binary when available instead of always downloading.","Retry once for 5xx; don't retry 404.","Pin tool versions when upstream is actively releasing."],"tags":["network","http-error","download","github-releases"],"backgroundTag":"download-failed-http-error","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}