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
- Read the status in the message: 403/429 → rate limited; 404 → repo/releases gone; 5xx → retry later.
- For rate limiting, wait for the rate-limit window to reset (check X-RateLimit-Reset) or use authenticated requests.
- Verify the tool's repo still publishes GitHub releases; if releases moved, update the TOOLS[tool].repo config.
- Retry with backoff for transient 5xx responses.
- 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
- Authenticate GitHub API requests when running on shared CI to avoid the 60 req/hr IP limit.
- Cache the last-known version and treat the API call as best-effort.
- Keep a pinned fallback version per tool.
- Watch GitHub status for 5xx windows before bulk downloads.
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
- GitHub API rate limit exceeded while fetching release metada
- Failed to fetch GitHub release metadata: ${response.statusTe
- Devin API error ${response.status} ${response.statusText}: $
- Failed to initiate device authorization: ${initiateResponse.
- GitHub release ${expectedTag} has no asset list
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/7ffced65af7495d3.
Report an issue: GitHub.