danny-avila/LibreChat · error
Failed to fetch URL: ${response.status} ${response.statusTex
Error message
Failed to fetch URL: ${response.status} ${response.statusText} What it means
Thrown by saveURLToAzure (Azure/crud.js) after fetching a remote file URL via node-fetch when response.ok is false. The fetch is gated by assertRemoteFileURL and carries timeout/size caps; this error surfaces a non-2xx status from the remote origin before any Azure upload is attempted.
Source
Thrown at api/server/services/Files/Azure/crud.js:79
* @param {string} [params.basePath='images'] - The base folder within the container.
* @param {string} [params.containerName] - The Azure Blob container name.
* @returns {Promise<string>} The URL of the uploaded blob.
*/
async function saveURLToAzure({
userId,
URL,
fileName,
basePath = defaultBasePath,
containerName,
}) {
try {
const maxBytes = getRemoteFileFetchMaxBytes();
const response = await fetch(assertRemoteFileURL(URL), {
timeout: getRemoteFileFetchTimeoutMs(),
size: maxBytes,
});
if (!response.ok) {
throw new Error(`Failed to fetch URL: ${response.status} ${response.statusText}`);
}
assertRemoteFileContentLength(response.headers, maxBytes);
const buffer = await response.buffer();
if (buffer.length > maxBytes) {
throw new Error(`Remote file response too large: ${buffer.length} bytes`);
}
return await saveBufferToAzure({ userId, buffer, fileName, basePath, containerName });
} catch (error) {
logger.error('[saveURLToAzure] Error uploading file from URL:', error);
throw error;
}
}
/**
* Retrieves a blob URL from Azure Blob Storage.
*
* @param {Object} paramsView on GitHub (pinned to 5ff282f900)
Solutions
- Verify the URL is publicly reachable with curl -I and returns 2xx.
- If the origin needs auth or custom headers, fetch through a proxy that injects them rather than passing the raw URL.
- Handle 403/404 distinctly in the caller to give the user an accurate message.
- Check that the URL scheme is http/https (assertRemoteFileURL also enforces this).
Example fix
// before
const response = await fetch(assertRemoteFileURL(URL), {...});
if (!response.ok) {
throw new Error(`Failed to fetch URL: ${response.status} ${response.statusText}`);
}
// after
const response = await fetch(assertRemoteFileURL(URL), {...});
if (!response.ok) {
const err = new Error(`Failed to fetch URL: ${response.status} ${response.statusText}`);
err.statusCode = response.status;
throw err;
} Defensive patterns
Strategy: validation
Validate before calling
// HEAD-check the URL before downloading
const head = await fetch(assertRemoteFileURL(URL), { method: 'HEAD', timeout: getRemoteFileFetchTimeoutMs() });
if (!head.ok) {
throw new Error(`Preflight failed: ${head.status} ${head.statusText}`);
}
// proceed to GET Try / catch
try {
await saveURLToAzure({ userId, URL, fileName });
} catch (err) {
const m = /^Failed to fetch URL: (\d{3})/.exec(err.message);
if (m) {
const status = Number(m[1]);
return res.status(status === 404 || status === 403 ? status : 502)
.json({ message: `Remote URL returned ${status}` });
}
throw err;
} Prevention
- Validate URLs are public and return 2xx with a HEAD preflight.
- Surface the remote status code to the user instead of a generic 500.
- Keep assertRemoteFileURL on the path to block non-http(s) schemes.
When it happens
Trigger: POST of a remote URL to the files endpoint resolves to a non-2xx HTTP status (404, 403, 500, etc.) from the origin server, or the origin returns a redirect chain that ends in an error.
Common situations: Expired/signed S3 URL passed as an image source; origin requires auth headers not supplied; URL is behind a paywall or geo-blocked; typo in the URL; origin server is down.
Related errors
- Remote file response too large: ${buffer.length} bytes
- Failed to fetch URL: ${response.status} ${response.statusTex
- User ID not found in blob path
- Request failed with status ${response.status}: ${json.error.
- Storage backend "${source}" does not support file writes
AI-assisted analysis of danny-avila/LibreChat@5ff282f900 (2026-08-12).
Data as JSON: /api/errors/023f95e01fdc24de.
Report an issue: GitHub.