{"record":{"id":"b82d2ada15745fb9","repo":"can1357/oh-my-pi","slug":"download-timed-out-url","errorCode":null,"errorMessage":"Download timed out: ${url}","messagePattern":"Download timed out: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/utils/tools-manager.ts","lineNumber":211,"sourceCode":"}\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();\n\tconst architecture = os.arch();\n\n\t// Get latest version\n\tconst version = await getLatestVersion(config.repo, signal);\n\n\t// Get asset name for this platform\n\tconst assetName = config.getAssetName(version, plat, architecture);","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/utils/tools-manager.ts#L193-L229","documentation":"Downloads are bounded by a timeout AbortSignal combined with any caller-provided signal. When the fetch or the body streaming (writeResponseBody) is aborted because the transfer exceeded the timeout, isAbortLikeError() matches and downloadFile rethrows this error naming the URL, so callers can distinguish slow downloads from other failures.","triggerScenarios":"The asset download via https://github.com/<repo>/releases/download/... takes longer than the download timeout — either the initial fetch hangs or the streamed body stalls mid-transfer (writeResponseBody aborts via downloadSignal).","commonSituations":"Large binaries (hundreds of MB) on slow connections, throttled corporate networks, unstable Wi-Fi dropping mid-transfer, or GitHub CDN slowness during peak load.","solutions":["Retry on a faster/more stable connection — partially downloaded temp files are cleaned up, so retries start fresh.","Increase the download timeout if your network is legitimately slow for large assets.","Pre-install the tool system-wide (apt/brew/cargo) so the manager finds it on PATH instead of downloading.","Check whether a proxy or VPN is throttling GitHub downloads and bypass it.","Download during off-peak hours if the CDN is congested."],"exampleFix":"// before: const p = await toolsManager.path(\"rg\") // throws \"Download timed out: https://github.com/...\" | // after: catch, and if err.message.startsWith(\"Download timed out:\"), use a system fallback like /usr/bin/rg; rethrow otherwise","handlingStrategy":"retry","validationCode":"// estimate feasibility: check asset size before downloading | const head = await fetch(assetUrl, { method: \"HEAD\" }); const sizeMb = Number(head.headers.get(\"content-length\") ?? 0) / 1e6; if (sizeMb > 500 && isSlowNetwork()) throw new Error(\"Asset too large for current link\");","typeGuard":"function isDownloadTimeout(err: unknown): err is Error { return err instanceof Error && err.message.startsWith(\"Download timed out: \"); }","tryCatchPattern":"try { const p = await toolsManager.path(\"rg\"); } catch (err) { if (isDownloadTimeout(err)) { /* use system binary or retry on stable network */ } else throw err; }","preventionTips":["Pre-install heavy tools via system package manager to skip large downloads.","Increase download timeouts on known-slow links.","Run downloads on stable connections; avoid cellular/VPN-throttled paths.","Implement one retry with backoff before surfacing to users."],"tags":["network","timeout","download"],"backgroundTag":"download-timeout","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}