{"record":{"id":"b2a9e92783b9ca9b","repo":"danny-avila/LibreChat","slug":"download-failed-response-status-response-sta","errorCode":null,"errorMessage":"Download failed: ${response.status} ${response.statusText}","messagePattern":"Download failed: (.+?) (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"client/src/data-provider/Files/sharepoint.ts","lineNumber":52,"sourceCode":"    file: SharePointFile;\n    accessToken: string;\n    onProgress?: (progress: SharePointDownloadProgress) => void;\n  }\n> => {\n  return useMutation({\n    mutationFn: async ({ file, accessToken, onProgress }) => {\n      const downloadUrl =\n        file.downloadUrl ||\n        `https://graph.microsoft.com/v1.0/drives/${file.driveId}/items/${file.itemId}/content`;\n\n      const response = await fetch(downloadUrl, {\n        headers: {\n          Authorization: `Bearer ${accessToken}`,\n        },\n      });\n\n      if (!response.ok) {\n        throw new Error(`Download failed: ${response.status} ${response.statusText}`);\n      }\n\n      const contentLength = parseInt(response.headers.get('content-length') || '0');\n      const reader = response.body?.getReader();\n      if (!reader) {\n        throw new Error('Failed to get response reader');\n      }\n\n      const chunks: Uint8Array[] = [];\n      let receivedLength = 0;\n\n      while (true) {\n        const { done, value } = await reader.read();\n\n        if (done) break;\n\n        chunks.push(value);\n        receivedLength += value.length;","sourceCodeStart":34,"sourceCodeEnd":70,"githubUrl":"https://github.com/danny-avila/LibreChat/blob/5ff282f9006c436e561de1afd39a481bea1ef0d8/client/src/data-provider/Files/sharepoint.ts#L34-L70","documentation":"Thrown by the single-file SharePoint download mutation when Microsoft Graph returns a non-2xx response for the file-content request. The download URL is either a pre-issued `file.downloadUrl` or a constructed Graph endpoint `https://graph.microsoft.com/v1.0/drives/{driveId}/items/{itemId}/content`, always called with `Authorization: Bearer {accessToken}`. The thrown message includes the HTTP status and statusText so the caller can distinguish 401/403/404.","triggerScenarios":"The Graph access token is expired or lacks the `Files.Read`/`Files.Read.All` scope (401/403); the drive item was deleted, moved, or the `driveId`/`itemId` are stale (404); the token is for a different tenant/user than the resource owner (403); Graph throttling returns 429/503.","commonSituations":"Token cached for 50 minutes but Graph rejected it (clock skew or early expiry); user selected a file in the SharePoint picker then lost access before download; SharePoint item moved/renamed after the picker resolved it; wrong Graph scope requested for Download vs Pick (the scope selection differs by `purpose`).","solutions":["Inspect the captured `response.status`/`statusText` in the thrown message — 401/403 means token/scope, 404 means the item is gone, 429/503 means retry with backoff.","For 401/403, force a token refresh (the hook already re-fetches via `refetchToken`) and confirm the Download scope (`sharePointPickerGraphScope`) includes a Files.Read permission.","For 404, re-open the SharePoint picker so a fresh `downloadUrl`/`driveId`/`itemId` is resolved.","For 429/503, retry with exponential backoff and respect the `Retry-After` header."],"exampleFix":"// before\nif (!response.ok) {\n  throw new Error(`Download failed: ${response.status} ${response.statusText}`);\n}\n// after — include item identity + surface retry guidance for transient errors\nif (!response.ok) {\n  const detail = `${response.status} ${response.statusText}`;\n  const err = new Error(`Download failed for ${file.driveId}/${file.itemId}: ${detail}`);\n  err.status = response.status;\n  err.retryable = response.status === 429 || response.status >= 500;\n  throw err;\n}","handlingStrategy":"retry","validationCode":"// Validate the file descriptor has the minimum fields for a Graph content request\nfunction isValidSharePointFile(f: SharePointFile): boolean {\n  return Boolean((f.downloadUrl || (f.driveId && f.itemId)) && f.name);\n}","typeGuard":"function isSharePointFile(f: unknown): f is SharePointFile {\n  return typeof f === 'object' && f !== null && typeof (f as any).name === 'string' &&\n    (typeof (f as any).downloadUrl === 'string' ||\n      (typeof (f as any).driveId === 'string' && typeof (f as any).itemId === 'string'));\n}","tryCatchPattern":"try {\n  const response = await fetch(downloadUrl, { headers: { Authorization: `Bearer ${accessToken}` } });\n  if (!response.ok) throw Object.assign(new Error(`Download failed: ${response.status}`), { status: response.status, retryable: response.status === 429 || response.status >= 500 });\n} catch (err) {\n  if (err.status === 401) { await refetchToken(); /* retry once */ }\n  else throw err;\n}","preventionTips":["Refresh the Graph token (50-min cache) before long downloads; retry once on 401.","Prefer pre-issued downloadUrl values; refresh the picker when they expire.","Handle 429/5xx with exponential backoff honoring Retry-After."],"tags":["sharepoint","microsoft-graph","network","file-download","http"],"backgroundTag":null,"analyzedSha":"5ff282f9006c436e561de1afd39a481bea1ef0d8","analyzedAt":"2026-08-12T21:38:08.145Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}