oven-sh/bun · error · Error
github ${path}: ${res.status}
Error message
github ${path}: ${res.status} What it means
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.
Source
Thrown at scripts/binary-size.ts:100
console.log(` ${triplet.padEnd(30)} ${fmtBytes(sizes[triplet]).padStart(10)}`);
}
await Bun.write(
"binary-sizes.json",
JSON.stringify({ build: buildNumber, branch, release: isRelease, sizes }, null, 2),
);
agent(["artifact", "upload", "binary-sizes.json"]);
// ─── Baselines ───
type Baseline = { label: string; href?: string; sizes: Sizes };
const ghToken = (await getSecret("GITHUB_TOKEN")) ?? process.env.GITHUB_TOKEN;
const ghHeaders: Record<string, string> = ghToken ? { Authorization: `Bearer ${ghToken}` } : {};
async function githubJson<T>(path: string): Promise<T> {
const res = await fetch(`https://api.github.com/repos/oven-sh/bun/${path}`, { headers: ghHeaders });
if (!res.ok) throw new Error(`github ${path}: ${res.status}`);
return res.json() as Promise<T>;
}
async function buildNumberForCommit(sha: string): Promise<number | undefined> {
const { statuses } = await githubJson<{ statuses: { context: string; target_url: string }[] }>(
`commits/${sha}/status`,
);
const bk = statuses.find(s => s.context.startsWith("buildkite/"));
const m = bk?.target_url.match(/\/builds\/(\d+)/);
return m ? parseInt(m[1], 10) : undefined;
}
async function sizesFromBuild(n: number): Promise<{ sizes: Sizes; release?: boolean } | undefined> {
const res = await fetch(`https://buildkite.com/${org}/${pipeline}/builds/${n}.json`);
if (!res.ok) return;
const { id } = (await res.json()) as { id: string };
const dir = "binary-size-tmp";
rmSync(dir, { recursive: true, force: true });View on GitHub (pinned to 8c5296ac45)
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
Example fix
# before $ bun scripts/binary-size.ts Error: github commits/<sha>/status: 403 # after $ export GITHUB_TOKEN=$(gh auth token) $ bun scripts/binary-size.ts
Defensive patterns
Strategy: retry
Validate before calling
const r = await fetch("https://api.github.com/rate_limit", { headers: ghHeaders });
const { rate: { remaining } } = await r.json();
if (remaining === 0) throw new Error("out of GitHub rate limit; export GITHUB_TOKEN or wait"); Type guard
const isGithubApiError = (e: unknown) =>
e instanceof Error && /^github \S+: \d{3}$/.test(e.message); Try / catch
for (let attempt = 1; ; attempt++) {
try { return await githubJson(path); }
catch (e) {
if (attempt === 3 || !isGithubApiError(e)) throw e;
if (e.message.endsWith("404")) throw e; // permanent, not transient
await new Promise(r => setTimeout(r, 2 ** attempt * 1000));
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- github ${p}: ${r.status} ${r.statusText}
- GitHub API rate limit exceeded after ${maxRetries} retries
- GITHUB_TOKEN environment variable is required
- [azure] Failed to get public IP for ${vmName}
- HEAD ${url}: ${head.status}
AI-assisted analysis of oven-sh/bun@8c5296ac45 (2026-08-16).
Data as JSON: /api/errors/7a18f45074a1a209.
Report an issue: GitHub.