musistudio/claude-code-router · error
The CCR artifact endpoint returned a non-media content type.
Error message
The CCR artifact endpoint returned a non-media content type.
What it means
The Content-Type returned by the CCR artifact endpoint is not a recognized image/* or video/* MIME type. mediaKind() maps declared MIME types to 'image' or 'video'; anything else (application/octet-stream, text/html, JSON error payloads) fails this guard before any bytes are buffered.
Source
Thrown at packages/core/src/agents/codex/media-preview-bridge.ts:308
return { artifactId, url };
}
async function loadCodexMediaArtifact(validated: ValidatedArtifactUrl, signal: AbortSignal): Promise<LoadedMediaArtifact> {
let response: Response;
try {
response = await fetch(validated.url, {
headers: { accept: "image/*, video/*" },
redirect: "error",
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) {View on GitHub (pinned to 99f24806c6)
Solutions
- Manually fetch the URL and inspect the raw Content-Type header to see what the server actually sends
- If the server mislabels media as application/octet-stream, fix the artifact upload to set the correct MIME type
- If the response is an HTML/JSON error page, investigate why the endpoint returned 200 with an error body
- Only request artifacts that are actually images or videos
Defensive patterns
Strategy: validation
Validate before calling
async function declaresMediaType(url: string): Promise<boolean> {
const res = await fetch(url, { method: 'HEAD' });
const ct = (res.headers.get('content-type') || '').split(';', 1)[0].trim().toLowerCase();
return ct.startsWith('image/') || ct.startsWith('video/');
} Type guard
function isNonMediaTypeRejection(e: unknown): boolean {
return e instanceof Error && e.message.includes('non-media content type');
} Try / catch
try {
const media = await bridge.artifact(ref);
} catch (e) {
if (isNonMediaTypeRejection(e)) return renderAsDownload(ref);
throw e;
} Prevention
- Only reference image/video attachments for preview
- Set correct MIME type metadata when uploading artifacts
- Watch for 200-status error pages masquerading as artifacts
When it happens
Trigger: The server serves the artifact with application/octet-stream or a missing/garbage Content-Type; the endpoint actually returned a JSON/HTML error page with a 200 status; a genuinely non-media artifact was referenced.
Common situations: CDN or object storage defaulting to application/octet-stream when metadata wasn't set; error pages that return 200; referencing an attachment whose kind isn't image or video.
Related errors
- The CCR media artifact exceeds the inline preview size limit
- Compressed CCR media artifacts are not accepted for inline p
- The CCR artifact response was empty.
- The CCR artifact content did not match its declared media ty
- duration is required for ${target.protocol}.
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/eb42230703d474e8.
Report an issue: GitHub.