musistudio/claude-code-router · error
The CCR artifact endpoint returned HTTP ${response.status}.
Error message
The CCR artifact endpoint returned HTTP ${response.status}. What it means
The HTTP response from the CCR artifact endpoint had a non-2xx status. loadCodexMediaArtifact checks response.ok after a successful fetch and rejects with the concrete status code so callers can distinguish auth failures (401/403), missing artifacts (404), and server errors (5xx).
Source
Thrown at packages/core/src/agents/codex/media-preview-bridge.ts:304
const token = url.searchParams.get("token") || "";
if (keys.length !== 1 || keys[0] !== "token" || !/^[A-Za-z0-9_-]{32}$/.test(token)) {
throw new Error("Artifact URL contains an invalid access token.");
}
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();View on GitHub (pinned to 99f24806c6)
Solutions
- Match the status in the message: 401/403 → refresh/re-establish the CCR session and retry; 404/410 → the artifact no longer exists, drop the preview; 5xx → retry with backoff
- Confirm the artifact reference and URL stored in the bridge still correspond to a live session
- Check CCR server health/logs if the status is consistently 5xx
Example fix
// before
const media = await bridge.artifact(ref);
// after
try {
const media = await bridge.artifact(ref);
} catch (e) {
if (/HTTP 4\d\d/.test(e.message)) { /* artifact unavailable; skip preview */ }
else if (/HTTP 5\d\d/.test(e.message)) { /* retry with backoff */ }
else throw e;
} Defensive patterns
Strategy: try-catch
Type guard
function isArtifactHttpError(e: unknown): number | null {
const m = e instanceof Error ? e.message.match(/HTTP (\d{3})/) : null;
return m ? Number(m[1]) : null;
} Try / catch
try {
const media = await bridge.artifact(ref);
} catch (e) {
const status = isArtifactHttpError(e);
if (status && status >= 500) return retryWithBackoff(() => bridge.artifact(ref));
if (status === 401 || status === 403) await refreshSession();
if (status === 404 || status === 410) return renderPlaceholder(ref);
throw e;
} Prevention
- Refresh session tokens before they expire
- Persist accurate artifact URLs in references
- Distinguish 4xx (permanent) from 5xx (retryable) in handling
When it happens
Trigger: artifact() request returns 401/403 (expired or invalid session token), 404 (artifact deleted or unknown id), 410 (expired artifact URL), or 5xx from the CCR server.
Common situations: The CCR session token expired between conversation start and artifact fetch; the artifact was garbage-collected on the server; the wrong artifact URL was stored in the reference; or the endpoint is behind a gateway returning 502/503 during deployments.
Related errors
- HTTP + response.status + from CCR remote sync
- The CCR artifact request failed.
- MCP HTTP request failed (${this.server.name}): ${response.st
- ZCode profiles can only open the app; agent arguments are no
- Claude Design profiles can only be opened from CCR Desktop.
AI-assisted analysis of musistudio/claude-code-router@99f24806c6 (2026-08-27).
Data as JSON: /api/errors/26da303036efeb50.
Report an issue: GitHub.