schollz/croc · error
GitHub returned invalid release metadata
Error message
GitHub returned invalid release metadata
What it means
Thrown by fetchLatestRelease() when GitHub returns 200 but the JSON body is not release-shaped: tag_name or html_url missing/falsy, or assets not an array. It protects the downstream asset-selection code (assetArchitecture / assets.find) from an unexpected payload shape.
Source
Thrown at web/src/releases.ts:138
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
- In tests, mock fetch with { tag_name, html_url, assets: [...] }
- Bypass or fix intermediaries that rewrite api.github.com responses
- Track the GitHub REST API changelog for release schema changes
Example fix
// before (test stub that triggers the error)
fetchMock.mockResolvedValue(new Response(JSON.stringify({}), { status: 200 }));
// after
fetchMock.mockResolvedValue(new Response(JSON.stringify({
tag_name: 'v1.0.0',
html_url: 'https://github.com/o/r/releases/v1.0.0',
assets: [],
}), { status: 200 })); Defensive patterns
Strategy: type-guard
Validate before calling
const body = await response.json();
if (!isGitHubRelease(body)) throw new Error('unexpected release payload shape'); Type guard
function isGitHubRelease(v: unknown): v is GitHubRelease {
const r = v as Record<string, unknown>;
return typeof r?.tag_name === 'string' && r.tag_name !== '' &&
typeof r?.html_url === 'string' && Array.isArray(r?.assets);
} Try / catch
try { return await fetchLatestRelease(signal); } catch (e) { if (e instanceof Error && e.message === 'GitHub returned invalid release metadata') invalidateReleaseCache(); throw e; } Prevention
- Stub fetch in tests with fixtures containing tag_name, html_url, assets
- Watch the GitHub REST changelog for release schema changes
When it happens
Trigger: A 200 response lacking tag_name/html_url/assets: a proxy returning an error page with 200, a test fetch mock returning {}, or a GitHub API schema change after deprecation.
Common situations: Test fixtures stubbing fetch with minimal objects; intercepting proxies rewriting responses; future GitHub API versions dropping fields.
Related errors
- Code must be at least 6 characters
- Custom codes must use printable ASCII characters
- Choose at least one file
- Duplicate filename: ${outgoingName}
- Received a file chunk outside the advertised file size
AI-assisted analysis of schollz/croc@e25f1bdc04 (2026-08-15).
Data as JSON: /api/errors/f1b420d249380f21.
Report an issue: GitHub.