can1357/oh-my-pi · error · Error

Download timed out: ${url}

Error message

Download timed out: ${url}

What it means

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.

Source

Thrown at packages/coding-agent/src/utils/tools-manager.ts:211

}

/** Download a tool asset without handing the streaming Response to Bun.write. */
export async function downloadFile(url: string, dest: string, signal?: AbortSignal): Promise<void> {
	const downloadSignal = ptree.combineSignals(signal, TOOL_DOWNLOAD_TIMEOUT_MS);
	let response: Response;
	try {
		response = await fetch(url, {
			signal: downloadSignal,
		});
		if (!response.ok) {
			throw new Error(`Failed to download: ${response.status}`);
		} else if (!response.body) {
			throw new Error("No response body");
		}
		await writeResponseBody(dest, response.body, downloadSignal);
	} catch (err) {
		if (isAbortLikeError(err)) {
			throw new Error(`Download timed out: ${url}`);
		}
		throw err;
	}
}

// Download and install a tool
async function downloadTool(tool: ToolName, signal?: AbortSignal): Promise<string> {
	const config = TOOLS[tool];
	if (!config) throw new Error(`Unknown tool: ${tool}`);

	const plat = os.platform();
	const architecture = os.arch();

	// Get latest version
	const version = await getLatestVersion(config.repo, signal);

	// Get asset name for this platform
	const assetName = config.getAssetName(version, plat, architecture);

View on GitHub (pinned to 9690622007)

Solutions

  1. Retry on a faster/more stable connection — partially downloaded temp files are cleaned up, so retries start fresh.
  2. Increase the download timeout if your network is legitimately slow for large assets.
  3. Pre-install the tool system-wide (apt/brew/cargo) so the manager finds it on PATH instead of downloading.
  4. Check whether a proxy or VPN is throttling GitHub downloads and bypass it.
  5. Download during off-peak hours if the CDN is congested.

Example fix

// 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
Defensive patterns

Strategy: retry

Validate before calling

// 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");

Type guard

function isDownloadTimeout(err: unknown): err is Error { return err instanceof Error && err.message.startsWith("Download timed out: "); }

Try / catch

try { const p = await toolsManager.path("rg"); } catch (err) { if (isDownloadTimeout(err)) { /* use system binary or retry on stable network */ } else throw err; }

Prevention

When it happens

Trigger: 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).

Common situations: Large binaries (hundreds of MB) on slow connections, throttled corporate networks, unstable Wi-Fi dropping mid-transfer, or GitHub CDN slowness during peak load.

Understand the failure class

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/b82d2ada15745fb9. Report an issue: GitHub.