musistudio/claude-code-router · error
The CCR artifact response had no body.
Error message
The CCR artifact response had no body.
What it means
The HTTP response succeeded and passed all header checks but response.body is null, so there is no stream to read. This happens with unusual fetch implementations or synthetic Response objects that carry headers without a body.
Source
Thrown at packages/core/src/agents/codex/media-preview-bridge.ts:317
signal
});
} catch {
throw new Error("The CCR artifact request failed.");
}
if (!response.ok) throw new Error(`The CCR artifact endpoint returned HTTP ${response.status}.`);
if (response.redirected) throw new Error("The CCR artifact endpoint attempted a redirect.");
const declaredMimeType = (response.headers.get("content-type") || "").split(";", 1)[0].trim().toLowerCase();
const declaredKind = mediaKind(declaredMimeType);
if (!declaredKind) throw new Error("The CCR artifact endpoint returned a non-media content type.");
const maxBytes = declaredKind === "video" ? codexMediaPreviewMaxVideoBytes : codexMediaPreviewMaxImageBytes;
const declaredLength = Number(response.headers.get("content-length") || "0");
if (declaredLength && (!Number.isSafeInteger(declaredLength) || declaredLength < 1 || declaredLength > maxBytes)) {
throw new Error("The CCR media artifact exceeds the inline preview size limit.");
}
if (response.headers.get("content-encoding") && response.headers.get("content-encoding") !== "identity") {
throw new Error("Compressed CCR media artifacts are not accepted for inline preview.");
}
if (!response.body) throw new Error("The CCR artifact response had no body.");
const reader = response.body.getReader();
const chunks: Buffer[] = [];
let total = 0;
while (true) {
const part = await reader.read();
if (part.done) break;
if (!part.value?.byteLength) continue;
total += part.value.byteLength;
if (total > maxBytes) {
await reader.cancel();
throw new Error("The CCR media artifact exceeds the inline preview size limit.");
}
chunks.push(Buffer.from(part.value));
}
if (!total) throw new Error("The CCR artifact response was empty.");
if (declaredLength && total !== declaredLength) throw new Error("The CCR artifact response length did not match its headers.");
const bytes = Buffer.concat(chunks, total);
const detectedMimeType = detectMediaMimeType(bytes);View on GitHub (pinned to 99f24806c6)
Solutions
- If testing, make the mocked Response include a real body (new Response(bytes) or a ReadableStream)
- Check the actual raw exchange with curl to confirm the server sends a body
- Ensure the runtime provides spec-compliant fetch with streaming bodies (Node >= 18 undici)
Example fix
// before (test stub without body)
global.fetch = async () => new Response(null, { headers }); // triggers error
// after
global.fetch = async () => new Response(bytes, { headers }); Defensive patterns
Strategy: try-catch
Type guard
function isNoBodyRejection(e: unknown): boolean {
return e instanceof Error && e.message.includes('had no body');
} Try / catch
try {
const media = await bridge.artifact(ref);
} catch (e) {
if (isNoBodyRejection(e)) return renderPlaceholder(ref);
throw e;
} Prevention
- In tests, mock fetch with Responses that include real bodies
- Use spec-compliant fetch runtimes (Node >= 18)
- Avoid interceptors that consume or strip response bodies
When it happens
Trigger: A fetch polyfill or mock returns a Response with body === null (e.g. constructed via new Response() without a body in tests); a HEAD-like response from a misbehaving server or interceptor; runtimes where streaming bodies aren't supported.
Common situations: Unit tests stubbing fetch with minimal Response objects; HTTP/2 or proxy middleware that strips the body; calling the endpoint with methods that yield no body.
Related errors
- HTTP + response.status + from CCR remote sync
- The CCR artifact request failed.
- The CCR artifact endpoint attempted a redirect.
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/5b5ec18484c0ffc5.
Report an issue: GitHub.