can1357/oh-my-pi · error · Error

Browser download failed (${response.status} ${response.statu

Error message

Browser download failed (${response.status} ${response.statusText}) from ${url}

What it means

downloadArchive streams the Chrome-for-Testing zip from storage.googleapis.com to disk; if the response is not ok or has no body, this Error is thrown with status, statusText, and the full URL. It indicates the binary download itself failed, distinct from the metadata fetch failure.

Source

Thrown at packages/utils/src/browsers.ts:344

async function pathExists(filePath: string): Promise<boolean> {
	try {
		await fsp.access(filePath);
		return true;
	} catch (error) {
		if (isMissingPath(error)) return false;
		throw error;
	}
}

async function downloadArchive(
	url: URL,
	destination: string,
	onProgress: ((progress: BrowserDownloadProgress) => void) | undefined,
): Promise<void> {
	const response = await fetch(url);
	if (!response.ok || !response.body) {
		throw new Error(`Browser download failed (${response.status} ${response.statusText}) from ${url}`);
	}
	const totalBytes = Number(response.headers.get("content-length") ?? 0);
	const file = await fsp.open(destination, "wx");
	let downloadedBytes = 0;
	try {
		const reader = response.body.getReader();
		for (;;) {
			const chunk = await reader.read();
			if (chunk.done) break;
			let offset = 0;
			while (offset < chunk.value.byteLength) {
				const write = await file.write(chunk.value, offset, chunk.value.byteLength - offset, null);
				if (write.bytesWritten === 0) throw new Error(`Browser download stalled while writing ${destination}`);
				offset += write.bytesWritten;
			}
			downloadedBytes += chunk.value.byteLength;
			onProgress?.({ downloadedBytes, totalBytes });
		}

View on GitHub (pinned to 9690622007)

Solutions

  1. Verify the buildId and platform combination exists: open the URL from the error message in a browser or check https://googlechromelabs.github.io/chrome-for-testing/known-good-versions-with-browsers.json.
  2. Retry with backoff for 429/5xx; serialize parallel installs in CI to avoid rate limits.
  3. Confirm egress to storage.googleapis.com (proxy/firewall allowlist).
  4. Use a known-good pinned buildId with a published browser artifact.

Example fix

// before
const buildId = '131.0'; // malformed -> 404 on archive GET
await install({ browser: Browser.CHROME, buildId, cacheDir });
// after
const buildId = '131.0.6778.204'; // exact version with published artifacts
await install({ browser: Browser.CHROME, buildId, cacheDir });
Defensive patterns

Strategy: retry

Validate before calling

// verify the artifact exists before install
const probe = await fetch(`https://storage.googleapis.com/chrome-for-testing-public/${buildId}/linux64/chrome-linux64.zip`, { method: 'HEAD' });
if (!probe.ok) throw new Error(`No Chrome archive for buildId=${buildId} platform=linux64 (HTTP ${probe.status})`);

Type guard

null

Try / catch

async function installWithRetry(opts: InstallOptions) {
  for (let attempt = 0; ; attempt++) {
    try {
      return await install(opts);
    } catch (err) {
      const m = /Browser download failed \((\d+) /.exec(String(err));
      if (m && (m[1].startsWith('5') || m[1] === '429') && attempt < 3) {
        await Bun.sleep(2 ** attempt * 1000); // backoff for 429/5xx
        continue;
      }
      throw err; // 4xx (bad buildId) will not heal by retrying
    }
  }
}

Prevention

When it happens

Trigger: install() -> downloadArchive when the archive GET returns non-2xx: wrong buildId (404, build never published for that platform), storage.googleapis.com 403/429 from rate limiting or blocked egress, or an ok status with a null body (e.g. 204 from a proxy).

Common situations: Typos or truncated buildIds in config (404); requesting builds for platforms that don't exist (404); corporate firewalls blocking storage.googleapis.com; GCS rate limits during large parallel CI installs.

Related errors


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