danny-avila/LibreChat · error · Error
Download failed: ${response.status} ${response.statusText}
Error message
Download failed: ${response.status} ${response.statusText} What it means
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.
Source
Thrown at client/src/data-provider/Files/sharepoint.ts:52
file: SharePointFile;
accessToken: string;
onProgress?: (progress: SharePointDownloadProgress) => void;
}
> => {
return useMutation({
mutationFn: async ({ file, accessToken, onProgress }) => {
const downloadUrl =
file.downloadUrl ||
`https://graph.microsoft.com/v1.0/drives/${file.driveId}/items/${file.itemId}/content`;
const response = await fetch(downloadUrl, {
headers: {
Authorization: `Bearer ${accessToken}`,
},
});
if (!response.ok) {
throw new Error(`Download failed: ${response.status} ${response.statusText}`);
}
const contentLength = parseInt(response.headers.get('content-length') || '0');
const reader = response.body?.getReader();
if (!reader) {
throw new Error('Failed to get response reader');
}
const chunks: Uint8Array[] = [];
let receivedLength = 0;
while (true) {
const { done, value } = await reader.read();
if (done) break;
chunks.push(value);
receivedLength += value.length;View on GitHub (pinned to 5ff282f900)
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.
Example fix
// before
if (!response.ok) {
throw new Error(`Download failed: ${response.status} ${response.statusText}`);
}
// after — include item identity + surface retry guidance for transient errors
if (!response.ok) {
const detail = `${response.status} ${response.statusText}`;
const err = new Error(`Download failed for ${file.driveId}/${file.itemId}: ${detail}`);
err.status = response.status;
err.retryable = response.status === 429 || response.status >= 500;
throw err;
} Defensive patterns
Strategy: retry
Validate before calling
// Validate the file descriptor has the minimum fields for a Graph content request
function isValidSharePointFile(f: SharePointFile): boolean {
return Boolean((f.downloadUrl || (f.driveId && f.itemId)) && f.name);
} Type guard
function isSharePointFile(f: unknown): f is SharePointFile {
return typeof f === 'object' && f !== null && typeof (f as any).name === 'string' &&
(typeof (f as any).downloadUrl === 'string' ||
(typeof (f as any).driveId === 'string' && typeof (f as any).itemId === 'string'));
} Try / catch
try {
const response = await fetch(downloadUrl, { headers: { Authorization: `Bearer ${accessToken}` } });
if (!response.ok) throw Object.assign(new Error(`Download failed: ${response.status}`), { status: response.status, retryable: response.status === 429 || response.status >= 500 });
} catch (err) {
if (err.status === 401) { await refetchToken(); /* retry once */ }
else throw err;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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`).
Related errors
- ${response.status} ${response.statusText}
- [retrieveRun] Failed to retrieve run data:
- Failed to send email via Mailgun
- No files provided for download
- Failed to obtain SharePoint access token
AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12).
Data as JSON: /api/errors/b2a9e92783b9ca9b.
Report an issue: GitHub.