can1357/oh-my-pi · error · Error

GitHub API rate limit exceeded while fetching release metada

Error message

GitHub API rate limit exceeded while fetching release metadata; retry later or set GITHUB_TOKEN or GH_TOKEN

What it means

GitHub rate-limits unauthenticated API requests (~60/hour per IP) and authenticated ones more generously. When the metadata request returns 429, or 403 while no GITHUB_TOKEN/GH_TOKEN is set (GitHub signals rate limiting via 403 for anonymous clients), the updater throws this message instead of the generic non-ok error so the remedy is obvious.

Source

Thrown at packages/coding-agent/src/cli/update-cli.ts:272

		"X-GitHub-Api-Version": "2022-11-28",
	};
	if (githubToken) headers.Authorization = `Bearer ${githubToken}`;

	let response: Response;
	try {
		response = await fetchImpl(`${GITHUB_API}/repos/${REPO}/releases/tags/${encodeURIComponent(tag)}`, {
			headers,
			signal: withTimeoutSignal(RELEASE_METADATA_TIMEOUT_MS),
		});
	} catch (err) {
		if (isTimeoutError(err)) {
			throw new Error("Timed out fetching GitHub release metadata after 30s", { cause: err });
		}
		if (isUnsupportedProxyError(err)) throw new Error(unsupportedProxyMessage(), { cause: err });
		throw err;
	}
	if ((response.status === 403 && !githubToken) || response.status === 429) {
		throw new Error(
			"GitHub API rate limit exceeded while fetching release metadata; retry later or set GITHUB_TOKEN or GH_TOKEN",
		);
	}
	if (!response.ok) {
		throw new Error(`Failed to fetch GitHub release metadata: ${response.statusText}`);
	}

	return resolveReleaseBinaryAsset(await response.json(), tag, binaryName, { allowPrerelease });
}

export interface VerifiedBinaryDownloadOptions {
	url: string;
	targetPath: string;
	expectedSize: number;
	expectedDigest: string;
	fetchImpl?: Fetch;
}

View on GitHub (pinned to 9690622007)

Solutions

  1. Set a GitHub token: export GITHUB_TOKEN=<personal access token> (GH_TOKEN also accepted), then retry.
  2. Wait for the rate-limit window to reset (check X-RateLimit-Reset header); anonymous limits reset hourly.
  3. Retry later if on shared CI infrastructure — or configure a token as a CI secret.
  4. Reduce polling frequency if a script is hitting the endpoint repeatedly.

Example fix

// before
omp update
// after
export GITHUB_TOKEN=ghp_xxxxxxxxxxxx
omp update
Defensive patterns

Strategy: retry

Validate before calling

const check = await fetch(`https://api.github.com/rate_limit`);
const { rate } = await check.json();
if (rate.remaining === 0) {
  console.error(`GitHub rate limit exhausted; resets at ${new Date(rate.reset * 1000).toISOString()}.`);
  process.exit(1);
}

Try / catch

try {
  await update();
} catch (err) {
  if (err instanceof Error && err.message.includes("rate limit exceeded")) {
    console.error("Set GITHUB_TOKEN to raise the GitHub API limit, or wait for the hourly reset.");
  } else throw err;
}

Prevention

When it happens

Trigger: getReleaseBinaryAsset receives response.status === 429, or response.status === 403 with githubToken undefined — checked immediately after the fetch, before the generic !response.ok branch.

Common situations: Shared CI egress IPs exhausting the anonymous quota, running updates repeatedly on the same IP without a token, proxies whose exit IP is already rate-limited, or automated scripts polling the releases endpoint.

Related errors


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