schollz/croc · error
GitHub release request failed (${response.status})
Error message
GitHub release request failed (${response.status}) What it means
Thrown by fetchLatestRelease() when the GitHub API request for the latest release completes with a non-ok HTTP status; the status code is embedded in the message. It distinguishes transport success from API failure before the response body is parsed as a release.
Source
Thrown at web/src/releases.ts:130
const preferredArchitecture =
architecture === "unknown"
? platform === "macOS"
? "arm64"
: "x64"
: architecture;
return (
assets.find((asset) => assetArchitecture(asset) === preferredArchitecture) ??
assets[0]
);
}
export async function fetchLatestRelease(signal?: AbortSignal) {
const response = await fetch(latestReleaseAPI, {
signal,
headers: { Accept: "application/vnd.github+json" },
});
if (!response.ok) {
throw new Error(`GitHub release request failed (${response.status})`);
}
const release = (await response.json()) as GitHubRelease;
if (
!release.tag_name ||
!release.html_url ||
!Array.isArray(release.assets)
) {
throw new Error("GitHub returned invalid release metadata");
}
return release;
}
View on GitHub (pinned to e25f1bdc04)
Solutions
- On 403, back off respecting X-RateLimit-Reset or add an Authorization header / GITHUB_TOKEN to raise the limit
- On 404, verify the repository and that a published (non-draft) release exists
- Cache the last successful release response and serve stale on failure
- Retry with exponential backoff for transient 5xx
Example fix
// before
const release = await fetchLatestRelease(signal);
// after
let release;
try {
release = await fetchLatestRelease(signal);
} catch (e) {
if (e instanceof Error && e.message.includes('(403)')) release = lastGoodRelease;
else throw e;
} Defensive patterns
Strategy: retry
Validate before calling
async function releaseEndpointHealthy(signal?: AbortSignal): Promise<boolean> {
const r = await fetch(latestReleaseAPI, { method: 'HEAD', signal });
return r.ok;
} Try / catch
try { return await fetchLatestRelease(signal); } catch (e) { if (e instanceof Error && /\(403\)/.test(e.message)) return lastGoodRelease; if (e instanceof Error && /\(5\d\d\)/.test(e.message)) return retryWithBackoff(() => fetchLatestRelease(signal), 3); throw e; } Prevention
- Cache the last good release payload and serve it stale on failure
- Add a GitHub token in CI / shared-IP environments; honor X-RateLimit-Reset before retrying
When it happens
Trigger: Calling fetchLatestRelease() when api.github.com returns 403 (unauthenticated rate limit of 60 req/hr/IP exhausted), 404 (repo or release missing), or a 5xx.
Common situations: CI pipelines polling the endpoint frequently; many users behind one NAT/proxy egress IP; GitHub incidents; repository renamed so the API 404s.
Related errors
- Could not load croc.wasm (${response.status})
- Sender did not confirm the croc PAKE handshake
- Sender did not secure the channel
- Sender cancelled
- close.m || "Sender cancelled"
AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15).
Data as JSON: /api/errors/976243a6824ae936.
Report an issue: GitHub.