bytedance/deer-flow · error
Failed to load artifact: ${response.status}
Error message
Failed to load artifact: ${response.status} What it means
Thrown when loading artifact content via range-GET fails and the status is not the special empty-file case (416 with total 0). The loader uses Range requests for previews, so 416 with a non-zero total (range past EOF after truncation) and 5xx from the Gateway both land here. The error only embeds the numeric status.
Source
Thrown at frontend/src/core/artifacts/loader.ts:63
const response = await fetch(url, {
cache: "no-store",
headers: full
? undefined
: { Range: `bytes=0-${ARTIFACT_PREVIEW_MAX_BYTES - 1}` },
});
const contentRange = parseContentRange(response.headers.get("Content-Range"));
if (response.status === 416 && contentRange?.total === 0) {
return {
content: "",
url,
truncated: false,
previewBytes: 0,
totalBytes: 0,
sha256: await sha256OfText(""),
};
}
if (!response.ok) {
throw new Error(`Failed to load artifact: ${response.status}`);
}
const bytes = await response.arrayBuffer();
const truncated =
!full &&
response.status === 206 &&
(contentRange?.end === undefined ||
contentRange.total > contentRange.end + 1);
// Streaming decode intentionally holds an incomplete trailing UTF-8 code
// point instead of fabricating U+FFFD at the range boundary.
const content = new TextDecoder().decode(bytes, { stream: truncated });
const etag = response.headers.get("etag");
const sha256 =
etag?.match(/^"([0-9a-f]{64})"$/)?.[1] ??
(!truncated ? await sha256OfText(content) : undefined);
const contentLengthHeader = response.headers.get("Content-Length");
const contentLength =
contentLengthHeader === null ? undefined : Number(contentLengthHeader);View on GitHub (pinned to 1dd6ba1acb)
Solutions
- Retry with full=true (no Range header) once — bypasses range-past-EOF 416s
- On 404, re-check the artifact list for the thread and drop dead entries from the UI
- Verify nginx forwards Range headers (proxy_set_header Range / proxy_pass behavior) if 200-for-206 symptoms appear
- Re-request from offset 0 with the current total to resync after truncation
Example fix
// before
const page = await loadArtifact(url, {full: false});
// after
try {
const page = await loadArtifact(url, {full: false});
} catch (e) {
if (e instanceof Error && e.message.includes(': 416')) {
return loadArtifact(url, {full: true}); // resync after size change
}
throw e;
} Defensive patterns
Strategy: fallback
Type guard
export function isArtifactLoadError(e: unknown, status?: number): boolean {
return e instanceof Error && /^Failed to load artifact: \d+$/.test(e.message);
} Try / catch
try {
return await loadArtifact(url, {full: false});
} catch (e) {
if (isArtifactLoadError(e) && e.message.endsWith(': 416')) {
return loadArtifact(url, {full: true}); // range desync: refetch whole
}
if (isArtifactLoadError(e) && e.message.endsWith(': 404')) {
return null; // artifact gone
}
throw e;
} Prevention
- Refetch preview from offset 0 after artifact size changes
- Handle 416-with-total-0 empty-file case separately (loader already does)
- Verify proxy passes Range headers when self-hosting nginx
When it happens
Trigger: Requesting a range beyond the artifact's current size (file shrank between HEAD and GET); artifact deleted mid-preview (404); Gateway/nginx misconfig dropping Range support so a 200-with-Range mismatch confuses downstream parsing; proxy 502 during Gateway restart.
Common situations: Previewing an artifact that an agent turn is actively rewriting; nginx serving stale cached metadata; opening an old link to a pruned thread's artifact.
Related errors
- HTTP ${response.status}: ${response.statusText}
- Failed to load MCP configuration
- Failed to update MCP configuration
- Failed to update MCP server
- setup-status failed: ${response.status}
AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14).
Data as JSON: /api/errors/c5610d9e619dcf66.
Report an issue: GitHub.