{"record":{"id":"7a18f45074a1a209","repo":"oven-sh/bun","slug":"github-path-res-status","errorCode":null,"errorMessage":"github ${path}: ${res.status}","messagePattern":"github (.+?): (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"scripts/binary-size.ts","lineNumber":100,"sourceCode":"  console.log(`  ${triplet.padEnd(30)} ${fmtBytes(sizes[triplet]).padStart(10)}`);\n}\n\nawait Bun.write(\n  \"binary-sizes.json\",\n  JSON.stringify({ build: buildNumber, branch, release: isRelease, sizes }, null, 2),\n);\nagent([\"artifact\", \"upload\", \"binary-sizes.json\"]);\n\n// ─── Baselines ───\n\ntype Baseline = { label: string; href?: string; sizes: Sizes };\n\nconst ghToken = (await getSecret(\"GITHUB_TOKEN\")) ?? process.env.GITHUB_TOKEN;\nconst ghHeaders: Record<string, string> = ghToken ? { Authorization: `Bearer ${ghToken}` } : {};\n\nasync function githubJson<T>(path: string): Promise<T> {\n  const res = await fetch(`https://api.github.com/repos/oven-sh/bun/${path}`, { headers: ghHeaders });\n  if (!res.ok) throw new Error(`github ${path}: ${res.status}`);\n  return res.json() as Promise<T>;\n}\n\nasync function buildNumberForCommit(sha: string): Promise<number | undefined> {\n  const { statuses } = await githubJson<{ statuses: { context: string; target_url: string }[] }>(\n    `commits/${sha}/status`,\n  );\n  const bk = statuses.find(s => s.context.startsWith(\"buildkite/\"));\n  const m = bk?.target_url.match(/\\/builds\\/(\\d+)/);\n  return m ? parseInt(m[1], 10) : undefined;\n}\n\nasync function sizesFromBuild(n: number): Promise<{ sizes: Sizes; release?: boolean } | undefined> {\n  const res = await fetch(`https://buildkite.com/${org}/${pipeline}/builds/${n}.json`);\n  if (!res.ok) return;\n  const { id } = (await res.json()) as { id: string };\n  const dir = \"binary-size-tmp\";\n  rmSync(dir, { recursive: true, force: true });","sourceCodeStart":82,"sourceCodeEnd":118,"githubUrl":"https://github.com/oven-sh/bun/blob/8c5296ac459e8252d3cd702f3fbcbb0c249d95d5/scripts/binary-size.ts#L82-L118","documentation":"githubJson() in scripts/binary-size.ts throws when any GitHub REST call to api.github.com/repos/oven-sh/bun/<path> returns non-2xx. It is used to map commits to BuildKite builds and fetch baselines; auth comes from getSecret(\"GITHUB_TOKEN\") ?? process.env.GITHUB_TOKEN.","triggerScenarios":"403/429 rate limiting (especially unauthenticated at 60 requests/hour), 401 from an expired or invalid token, 404 when a commit SHA or its combined status has no data, or GitHub 5xx incidents.","commonSituations":"Running binary-size locally without GITHUB_TOKEN exported; a CI token lacking read scope for oven-sh/bun; querying a SHA from a force-pushed branch; running during a GitHub outage.","solutions":["Export a valid GITHUB_TOKEN (public-repo read is sufficient)","On 403/429: wait for the rate-limit window (check X-RateLimit-Reset) or use a token with a higher limit","On 404: verify the commit SHA exists on oven-sh/bun","Retry once after backoff for transient 5xx"],"exampleFix":"# before\n$ bun scripts/binary-size.ts\nError: github commits/<sha>/status: 403\n\n# after\n$ export GITHUB_TOKEN=$(gh auth token)\n$ bun scripts/binary-size.ts","handlingStrategy":"retry","validationCode":"const r = await fetch(\"https://api.github.com/rate_limit\", { headers: ghHeaders });\nconst { rate: { remaining } } = await r.json();\nif (remaining === 0) throw new Error(\"out of GitHub rate limit; export GITHUB_TOKEN or wait\");","typeGuard":"const isGithubApiError = (e: unknown) =>\n  e instanceof Error && /^github \\S+: \\d{3}$/.test(e.message);","tryCatchPattern":"for (let attempt = 1; ; attempt++) {\n  try { return await githubJson(path); }\n  catch (e) {\n    if (attempt === 3 || !isGithubApiError(e)) throw e;\n    if (e.message.endsWith(\"404\")) throw e; // permanent, not transient\n    await new Promise(r => setTimeout(r, 2 ** attempt * 1000));\n  }\n}","preventionTips":["Always run with GITHUB_TOKEN set — the anonymous 60/h limit is too small","Treat 404 as permanent and 403/429/5xx as transient","Cache commit-to-build lookups so repeated runs do not re-query"],"tags":["github-api","network","ci","binary-size","rate-limit"],"backgroundTag":null,"analyzedSha":"8c5296ac459e8252d3cd702f3fbcbb0c249d95d5","analyzedAt":"2026-08-16T08:01:58.794Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}