{"record":{"id":"fb43ccc5beee8b78","repo":"can1357/oh-my-pi","slug":"failed-to-fetch-chrome-for-testing-metadata-res","errorCode":null,"errorMessage":"Failed to fetch Chrome-for-Testing metadata (${response.status} ${response.statusText})","messagePattern":"Failed to fetch Chrome-for-Testing metadata \\((.+?) (.+?)\\)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/utils/src/browsers.ts","lineNumber":290,"sourceCode":"function chromeChannelName(tag: string): string | undefined {\n\tswitch (tag) {\n\t\tcase BrowserTag.STABLE:\n\t\t\treturn \"Stable\";\n\t\tcase BrowserTag.BETA:\n\t\t\treturn \"Beta\";\n\t\tcase BrowserTag.DEV:\n\t\t\treturn \"Dev\";\n\t\tcase BrowserTag.CANARY:\n\t\t\treturn \"Canary\";\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\nasync function fetchMetadata<T>(filename: string): Promise<T> {\n\tconst response = await fetch(`${CHROME_METADATA_BASE_URL}/${filename}`);\n\tif (!response.ok)\n\t\tthrow new Error(`Failed to fetch Chrome-for-Testing metadata (${response.status} ${response.statusText})`);\n\treturn (await response.json()) as T;\n}\n\nfunction chromeArchivePlatform(platform: BrowserPlatform): string {\n\tswitch (platform) {\n\t\tcase BrowserPlatform.LINUX:\n\t\tcase BrowserPlatform.LINUX_ARM:\n\t\t\treturn \"linux64\";\n\t\tcase BrowserPlatform.MAC:\n\t\t\treturn \"mac-x64\";\n\t\tcase BrowserPlatform.MAC_ARM:\n\t\t\treturn \"mac-arm64\";\n\t\tcase BrowserPlatform.WIN32:\n\t\t\treturn \"win32\";\n\t\tcase BrowserPlatform.WIN64:\n\t\t\treturn \"win64\";\n\t}\n}","sourceCodeStart":272,"sourceCodeEnd":308,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/utils/src/browsers.ts#L272-L308","documentation":"fetchMetadata fetches Chrome-for-Testing JSON metadata (last-known-good-versions, latest-versions-per-milestone, known-good-versions) from googlechromelabs.github.io; when the HTTP response is not ok it throws with the status and statusText. This is a network/service-level failure upstream of version resolution.","triggerScenarios":"Any call chain that resolves versions — resolveBuildId for channels or milestones — when the metadata request returns a non-2xx status (404 for a renamed file, 403 rate-limit/block, 5xx outage, captive-portal 200->no wait, non-ok only).","commonSituations":"Corporate proxies blocking googlechromelabs.github.io; GitHub Pages outage (5xx); DNS/connectivity issues surfacing as fetch errors earlier; stale pinned metadata URLs after an upstream rename.","solutions":["Retry with backoff — GitHub Pages outages are usually transient.","Check network/proxy access to https://googlechromelabs.github.io/chrome-for-testing/ from the failing environment.","Cache a known-good metadata file locally and pass resolved buildIds directly (exact version strings skip metadata entirely).","Pin buildIds in config to avoid metadata fetches at runtime."],"exampleFix":"// before\nconst buildId = await resolveBuildId(Browser.CHROME, platform, BrowserTag.STABLE); // fetch fails\n// after\nconst buildId = process.env.CHROME_BUILD_ID ?? await resolveBuildId(Browser.CHROME, platform, BrowserTag.STABLE);","handlingStrategy":"retry","validationCode":"// probe metadata availability before resolving versions\nconst res = await fetch('https://googlechromelabs.github.io/chrome-for-testing/last-known-good-versions.json');\nif (!res.ok) throw new Error(`CfT metadata unreachable (${res.status}); pin a buildId or retry later`);","typeGuard":"null","tryCatchPattern":"async function resolveWithRetry(...args: Parameters<typeof resolveBuildId>) {\n  for (let attempt = 0; ; attempt++) {\n    try {\n      return await resolveBuildId(...args);\n    } catch (err) {\n      if (/Failed to fetch Chrome-for-Testing metadata/.test(String(err)) && attempt < 3) {\n        await Bun.sleep(2 ** attempt * 1000); // backoff for transient GitHub Pages outages\n        continue;\n      }\n      throw err;\n    }\n  }\n}","preventionTips":["Allowlist googlechromelabs.github.io in corporate proxies/firewalls.","Cache metadata JSON locally with a TTL for offline resilience.","Pin exact buildIds to skip metadata fetches entirely.","Retry with exponential backoff on transient 5xx."],"tags":["network","http","metadata","chrome-for-testing"],"backgroundTag":"metadata-fetch-failed","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}