{"record":{"id":"fe5ede53f8472a78","repo":"bytedance/deer-flow","slug":"failed-to-list-uploaded-files","errorCode":null,"errorMessage":"Failed to list uploaded files","messagePattern":"Failed to list uploaded files","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"frontend/src/core/uploads/api.ts","lineNumber":104,"sourceCode":"      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) {\n    throw new Error(\n      await readErrorDetail(response, \"Failed to list uploaded files\"),\n    );\n  }\n\n  return response.json();\n}\n\n/**\n * Delete an uploaded file\n */\nexport async function deleteUploadedFile(\n  threadId: string,\n  filename: string,\n): Promise<{ success: boolean; message: string }> {\n  const encodedFilename = encodeURIComponent(filename);\n  const response = await fetch(\n    `${getBackendBaseURL()}/api/threads/${threadId}/uploads/${encodedFilename}`,\n    {","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/frontend/src/core/uploads/api.ts#L86-L122","documentation":"listUploadedFiles GETs /api/threads/{threadId}/uploads/list to enumerate a thread's uploaded files, throwing on any non-ok response with the gateway's detail or the 'Failed to list uploaded files' fallback.","triggerScenarios":"Listing files for a deleted thread (404), expired session (401), or gateway storage error (5xx). Also triggered when the route is absent because uploads are disabled in this deployment.","commonSituations":"Opening a thread's attachments panel after the thread was pruned server-side; background tab with a stale session triggering the list query on focus.","solutions":["Confirm the /uploads/list status code in the Network tab.","404: treat as 'no files' if the thread is known-deleted, otherwise correct the thread id.","401: re-auth and refetch.","5xx: check gateway logs and the storage backend mount."],"exampleFix":"// before: any failure surfaces as an error toast\nconst files = await listUploadedFiles(threadId);\n\n// after: 404 degrades to an empty list\nconst res = await fetch(url);\nif (res.status === 404) { return { files: [] }; }","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"let files: ListFilesResponse;\ntry { files = await listUploadedFiles(threadId); } catch (e) { if (isNotFound(e)) files = { files: [] }; else { toast(e.message); files = { files: [] }; } }","preventionTips":["Use React Query with retry only for transient statuses; render an empty list on 404.","Refresh the list after uploads and deletes to avoid stale UI.","Centralize readErrorDetail so status codes stay attached for branching."],"tags":["upload","api","files","frontend"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}