{"record":{"id":"5321d72c9cabfabd","repo":"langfuse/langfuse","slug":"failed-to-download-trace-json","errorCode":null,"errorMessage":"Failed to download trace JSON","messagePattern":"Failed to download trace JSON","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"web/src/features/traces/fns/downloadTrace.ts","lineNumber":60,"sourceCode":"  link.download = filename;\n  document.body.appendChild(link);\n  link.click();\n  document.body.removeChild(link);\n  URL.revokeObjectURL(url);\n}\n\nexport async function downloadServerTraceAsJson(\n  params: ServerTraceDownloadParams,\n) {\n  const { traceId, projectId } = params;\n  const response = await fetch(buildTraceDownloadUrl({ traceId, projectId }), {\n    method: \"GET\",\n    credentials: \"same-origin\",\n  });\n\n  if (!response.ok) {\n    const errorBody: unknown = await response.json().catch(() => null);\n    throw new Error(\n      hasErrorMessage(errorBody)\n        ? errorBody.message\n        : \"Failed to download trace JSON\",\n    );\n  }\n\n  const blob = await response.blob();\n  downloadBlob({\n    blob,\n    filename: `trace-${encodeURIComponent(traceId)}.json`,\n  });\n}\n\nexport function downloadLegacyTraceAsJson(params: LegacyTraceDownloadParams) {\n  const { trace, observations, filename } = params;\n  const exportData = {\n    trace,\n    observations,","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/langfuse/langfuse/blob/59d92c7cf365150d10b753b5a0d1708902a2ed60/web/src/features/traces/fns/downloadTrace.ts#L42-L78","documentation":"Fallback error from downloadServerTraceAsJson when the GET to the trace export endpoint returns a non-ok response and the body either has no message field or is not JSON. The server's message is preferred when present, so seeing this literal string means the response body was unparseable or message-less.","triggerScenarios":"GET /api/public/traces/{traceId}/export (or the internal download route) returning 404 (trace missing), 401/403 (no access), 413 (trace too large), or an HTML error page from a proxy with a non-JSON body.","commonSituations":"Trace deleted between viewing and downloading; expired session hitting an auth-redirect HTML page; reverse proxy (nginx/Cloudflare) returning 502 HTML; trace exceeding LANGFUSE_API_TRACE_OBSERVATIONS_SIZE_LIMIT_BYTES.","solutions":["Inspect response.status in the catch — 404 means the trace id is wrong/deleted, 401/403 means auth, 413 means too large","Re-check the traceId and re-authenticate, then retry the download","For 413, reduce trace size or raise LANGFUSE_API_TRACE_OBSERVATIONS_SIZE_LIMIT_BYTES on self-host"],"exampleFix":"// before\nif (!response.ok) {\n  const errorBody: unknown = await response.json().catch(() => null);\n  throw new Error(hasErrorMessage(errorBody) ? errorBody.message : \"Failed to download trace JSON\");\n}\n\n// after (include status for diagnosability)\nif (!response.ok) {\n  const errorBody: unknown = await response.json().catch(() => null);\n  throw new Error(\n    hasErrorMessage(errorBody)\n      ? `${errorBody.message} (HTTP ${response.status})`\n      : `Failed to download trace JSON (HTTP ${response.status})`,\n  );\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  await downloadServerTraceAsJson(traceId);\n} catch (e) {\n  const msg = e instanceof Error ? e.message : String(e);\n  if (/HTTP 404|not found/i.test(msg)) notifyTraceMissing();\n  else if (/HTTP 413|too large/i.test(msg)) notifyTooLarge();\n  else notifyDownloadFailed(msg);\n}","preventionTips":["Verify the trace exists in the UI before offering the download button","Handle non-JSON proxy error bodies by also checking response.status"],"tags":["download","trace","http","export"],"backgroundTag":"http-request-failed","analyzedSha":"59d92c7cf365150d10b753b5a0d1708902a2ed60","analyzedAt":"2026-08-27T22:22:00.402Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}