Hmbown/CodeWhale · error
Missing release response
Error message
Missing release response
What it means
boundedJson streams a Response body up to a size limit and JSON-parses it; it throws "Missing release response" immediately when response.body is null. This happens when the runtime hands back a body-less Response (e.g. certain redirects, opaque responses, or platform edge cases), so the release/receipt fetchers cannot read release data at all.
Solutions
- Check response.ok and response.body before passing to boundedJson and fail with a clearer error naming the URL.
- Create a fresh fetch for each call — never reuse a Response whose body may already be consumed.
- If the upstream is flaky, retry the fetch once before giving up.
- In tests, construct the Response with an explicit body: new Response(JSON.stringify(data), { status: 200 }).
Example fix
// before
const json = await boundedJson(res, LIMIT);
// after
if (!res.ok || !res.body) throw new Error(`release fetch failed: ${res.status}`);
const json = await boundedJson(res, LIMIT); Defensive patterns
Strategy: try-catch
Validate before calling
if (!res.ok || !res.body) throw new Error(`release fetch failed for ${url}: status=${res.status}`); Type guard
const hasBody = (res) => res instanceof Response && res.body !== null;
Try / catch
try {
const data = await boundedJson(res, LIMIT);
} catch (e) {
if (e.message === 'Missing release response') {
// retry once with a fresh fetch, then surface a clear error
const fresh = await fetch(url, { redirect: 'follow' });
return getComputerUseRelease(...);
}
throw e;
} Prevention
- Always fetch a fresh Response per call; never reuse consumed responses.
- Follow redirects explicitly so the body-bearing response is returned.
- In tests, construct Response objects with real bodies.
- Check res.ok and body presence at the call site for clearer diagnostics.
When it happens
Trigger: A fetch of the release manifest/asset returns a Response whose body is null — typically from a network stack quirk, an already-consumed response, or a redirect the runtime did not follow with a body.
Common situations: Cloudflare Workers fetch returning a null body for certain upstream errors; passing a synthetic Response created without a body in tests; calling the fetcher twice and reusing a consumed response.
Related errors
- returned HTTP with content type ; expected JSON
- building bundle fetch client failed
- bundle fetch failed with HTTP status
- bundle fetch request failed
- bundle redirects may not change URL scheme
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/fccacbfa437c0c74.
Report an issue: GitHub.
Appendix: source
Thrown at web/lib/computer-use-release.ts:92
if (receipt.version !== version || receipt.archive !== archive || receipt.platform !== "macos"
|| receipt.arch !== "universal" || receipt.notarized !== true
|| receipt.sha256 !== sha256 || receipt.size !== zip.size) return { status: "pending" };
// The image is offered only when the receipt and GitHub's digest agree on it; otherwise the archive alone is offered.
const image = receiptImage(receipt, version);
const dmg = assets.dmg && image && (assets.dmg.digest as string).slice(7) === image.sha256 && assets.dmg.size === image.size
? { downloadUrl: assets.dmg.browser_download_url as string, size: image.size, sha256: image.sha256 } : undefined;
return {
status: "ready", version, sha256, size: zip.size as number,
url: `${COMPUTER_USE_REPO}/releases/tag/v${version}`,
downloadUrl: zip.browser_download_url as string,
receiptUrl: assets.receipt.browser_download_url as string,
verification: "github-digest",
...(dmg ? { dmg } : {}),
};
}
async function boundedJson(response: Response, limit: number): Promise<unknown> {
if (!response.body) throw new Error("Missing release response");
const reader = response.body.getReader();
const decoder = new TextDecoder();
let length = 0, text = "";
try {
for (;;) {
const { done, value } = await reader.read();
if (done) break;
length += value.byteLength;
if (length > limit) throw new Error("Release response exceeds size limit");
text += decoder.decode(value, { stream: true });
}
return JSON.parse(text + decoder.decode());
} finally { await reader.cancel(); reader.releaseLock(); }
}
const WEB_HEADERS = { "User-Agent": "codewhale-web" };
/** GET a release web endpoint, following at most three 302s and only onto GitHub's release hosts over https. */View on GitHub (pinned to 433685b202)