can1357/oh-my-pi · error · Error

GitHub API error: ${response.status}

Error message

GitHub API error: ${response.status}

What it means

After fetching the latest-release endpoint, getLatestVersion() checks response.ok. Any non-2xx status (404 repo missing, 403 rate limited, 5xx server errors) is thrown as this error carrying the numeric HTTP status, giving callers a direct signal of what GitHub rejected.

Source

Thrown at packages/coding-agent/src/utils/tools-manager.ts:188

}

// Fetch latest release version from GitHub
async function getLatestVersion(repo: string, signal?: AbortSignal): Promise<string> {
	let response: Response;
	try {
		response = await fetch(`https://api.github.com/repos/${repo}/releases/latest`, {
			headers: { "User-Agent": USER_AGENT },
			signal: ptree.combineSignals(signal, TOOL_METADATA_TIMEOUT_MS),
		});
	} catch (err) {
		if (err instanceof Error && err.name === "AbortError") {
			throw new Error("GitHub API request timed out");
		}
		throw err;
	}

	if (!response.ok) {
		throw new Error(`GitHub API error: ${response.status}`);
	}

	const data = (await response.json()) as { tag_name: string };
	return data.tag_name.replace(/^v/, "");
}

/** Download a tool asset without handing the streaming Response to Bun.write. */
export async function downloadFile(url: string, dest: string, signal?: AbortSignal): Promise<void> {
	const downloadSignal = ptree.combineSignals(signal, TOOL_DOWNLOAD_TIMEOUT_MS);
	let response: Response;
	try {
		response = await fetch(url, {
			signal: downloadSignal,
		});
		if (!response.ok) {
			throw new Error(`Failed to download: ${response.status}`);
		} else if (!response.body) {
			throw new Error("No response body");

View on GitHub (pinned to 9690622007)

Solutions

  1. Read the status in the message: 403/429 → rate limited; 404 → repo/releases gone; 5xx → retry later.
  2. For rate limiting, wait for the rate-limit window to reset (check X-RateLimit-Reset) or use authenticated requests.
  3. Verify the tool's repo still publishes GitHub releases; if releases moved, update the TOOLS[tool].repo config.
  4. Retry with backoff for transient 5xx responses.
  5. If the status persists, install the tool manually and skip the auto-update path.

Example fix

// before: const version = await toolsManager.version("rg") // throws "GitHub API error: 403" | // after: catch, and if /GitHub API error: (403|429)/ matches, fall back to pinned version; rethrow otherwise
Defensive patterns

Strategy: fallback

Validate before calling

// check unauthenticated rate budget before calling | const rl = await (await fetch("https://api.github.com/rate_limit")).json(); if (rl.resources.core.remaining === 0) throw new Error("GitHub rate limit exhausted");

Type guard

function isGitHubApiError(err: unknown): err is Error { return err instanceof Error && /^GitHub API error: \d+$/.test(err.message); }

Try / catch

try { const version = await toolsManager.version("sg"); } catch (err) { if (/GitHub API error: (403|429)/.test(err.message)) { /* rate limited: cached version or authenticated request */ } else if (/GitHub API error: 5\d\d/.test(err.message)) { /* transient: retry later */ } else throw err; }

Prevention

When it happens

Trigger: The GET to https://api.github.com/repos/<repo>/releases/latest completes but returns a non-OK status — e.g. 403 with rate-limit exhausted (unauthenticated GitHub API allows ~60 req/hr per IP), 404 when the configured repo or its releases no longer exist, or 5xx during GitHub incidents.

Common situations: Shared CI runners exhausting the unauthenticated GitHub rate limit, a tool upstream renaming/removing its repo or stopping publishing GitHub releases, firewalled networks returning error pages, transient GitHub 5xx outages.

Related errors


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