paperclipai/paperclip · error
${body?.error ?? `Trace download failed: ${response.status}`
Error message
${body?.error ?? `Trace download failed: ${response.status}`} What it means
The heartbeats API trace-download helper throws this Error when fetching a heartbeat trace file returns non-OK. It prefers the server's `error` field from the JSON body and otherwise reports `Trace download failed: <status>`. Tenant session recovery is attempted before throwing.
Source
Thrown at ui/src/api/heartbeats.ts:180
{},
),
deleteProviderTrace: (runId: string) =>
api.delete<{ ok: true }>(`/heartbeat-runs/${runId}/provider-trace`),
downloadProviderTrace: async (runId: string): Promise<Blob> => {
const response = await fetch(
`/api/heartbeat-runs/${runId}/provider-trace/download`,
{
credentials: "include",
headers: { Accept: "application/x-ndjson" },
},
);
if (!response.ok) {
const body = (await response.json().catch(() => null)) as {
error?: string;
} | null;
const recovery = tenantSessionRecovery.recoverIfNeeded(response.status, body);
if (recovery) return recovery;
throw new Error(
body?.error ?? `Trace download failed: ${response.status}`,
);
}
return response.blob();
},
workspaceOperationLog: (
operationId: string,
offset = 0,
limitBytes = 256000,
) =>
api.get<{
operationId: string;
store: string;
logRef: string;
content: string;
nextOffset?: number;
}>(
`/workspace-operations/${operationId}/log?offset=${encodeURIComponent(String(offset))}&limitBytes=${encodeURIComponent(String(limitBytes))}`,View on GitHub (pinned to 01ad858492)
Solutions
- Confirm the heartbeat run still exists and its trace was persisted
- Check the download URL/id corresponds to the right company
- Check server storage/logs for trace write failures
- Retry transient 5xx with backoff
Example fix
// before
throw new Error(body?.error ?? `Trace download failed: ${response.status}`);
// after
if (response.status === 404) throw new Error('Trace artifact is no longer available.');
throw new Error(body?.error ?? `Trace download failed: ${response.status}`); Defensive patterns
Strategy: try-catch
Validate before calling
if (!heartbeat?.traceAvailable) throw new Error('No trace artifact for this run'); Type guard
function hasTraceError(b: unknown): b is { error: string } { return typeof b === 'object' && b !== null && typeof (b as any).error === 'string'; } Try / catch
try { const blob = await heartbeatsApi.downloadTrace(id); } catch (e) { if (/Trace download failed: 404/.test(e.message)) showToast('Trace expired'); else if (/failed: 5/.test(e.message)) retryDownload(); else throw e; } Prevention
- Check trace availability metadata before offering the download link
- Verify company scoping on the trace URL
- Retry 5xx downloads with backoff
- Alert on server-side trace persistence failures
When it happens
Trigger: Trace blob endpoint returns 404 (trace file pruned or never written), 403 (wrong company scope), or 500 (storage failure); response body is non-JSON so body is null.
Common situations: Old heartbeat whose trace artifacts were garbage-collected, trace larger than storage limits causing server 500, agent key lacking access to the company that owns the run.
Understand the failure class
Background: "API error: {status}" and "HTTP 401/403/404/429/5xx" errors: non-2xx HTTP responses explained — this error's family across 27 libraries.
Related errors
- Anthropic Managed Agents request failed with HTTP ${response
- The bridge host reached its reserved process body byte ceili
- OpenCode resumed a different session
- OpenCode session creation omitted its id
- OpenCode event stream returned HTTP ${response.status}
AI-assisted analysis of paperclipai/paperclip@01ad858492 (2026-09-10).
Data as JSON: /api/errors/e10065a9ca617247.
Report an issue: GitHub.