{"record":{"id":"d8f7e7b2c5aaf41b","repo":"bytedance/deer-flow","slug":"failed-to-load-upload-limits","errorCode":null,"errorMessage":"Failed to load upload limits","messagePattern":"Failed to load upload limits","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"frontend/src/core/uploads/api.ts","lineNumber":85,"sourceCode":"  );\n\n  if (!response.ok) {\n    throw new Error(await readErrorDetail(response, \"Upload failed\"));\n  }\n\n  return response.json();\n}\n\n/**\n * Load the upload limits enforced by the gateway for a thread\n */\nexport async function getUploadLimits(threadId: string): Promise<UploadLimits> {\n  const response = await fetch(\n    `${getBackendBaseURL()}/api/threads/${threadId}/uploads/limits`,\n  );\n\n  if (!response.ok) {\n    throw new Error(\n      await readErrorDetail(response, \"Failed to load upload limits\"),\n    );\n  }\n\n  return response.json();\n}\n\n/**\n * List all uploaded files for a thread\n */\nexport async function listUploadedFiles(\n  threadId: string,\n): Promise<ListFilesResponse> {\n  const response = await fetch(\n    `${getBackendBaseURL()}/api/threads/${threadId}/uploads/list`,\n  );\n\n  if (!response.ok) {","sourceCodeStart":67,"sourceCodeEnd":103,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/frontend/src/core/uploads/api.ts#L67-L103","documentation":"getUploadLimits GETs /api/threads/{threadId}/uploads/limits and throws on non-ok, with the gateway detail preferred over this fallback text. The response feeds client-side validation of file size/count before uploading.","triggerScenarios":"Calling the limits endpoint for a thread id the gateway does not know (404), unauthenticated access (401), or the gateway config missing upload settings causing a handler error (500).","commonSituations":"Opening the attachment picker for a thread created before a server migration; session expired so the limits prefetch fails; uploads feature disabled in gateway config making the route 404/405.","solutions":["Check the status of the /uploads/limits request; 404 usually means uploads are disabled or the thread id is stale.","401: refresh auth and let the query retry.","If uploads are meant to be enabled, verify the gateway config's upload section and route registration.","On repeated 5xx, inspect gateway logs for the limits handler."],"exampleFix":"// before: unguarded prefetch fails the whole picker\nconst limits = await getUploadLimits(threadId);\n\n// after: degrade gracefully when limits are unavailable\nlet limits: UploadLimits | null = null;\ntry { limits = await getUploadLimits(threadId); }\ncatch { /* fall back to client-side default limits */ }","handlingStrategy":"fallback","validationCode":"if (!threadId) { /* skip limits fetch for threads not yet created */ }","typeGuard":"function canQueryLimits(threadId: unknown): threadId is string { return typeof threadId === \"string\" && threadId.length > 0; }","tryCatchPattern":"let limits: UploadLimits | null = null;\ntry { limits = await getUploadLimits(threadId); } catch { limits = null; } // proceed with conservative client defaults","preventionTips":["Treat limits as an enhancement, not a hard dependency, of the attach flow.","Cache limits per thread to avoid repeated failing calls.","Distinguish 404 (uploads disabled) from 401 (auth) in logs."],"tags":["upload","limits","api","frontend"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}