overleaf/overleaf · error · RequestFailedError
request failed
Error message
request failed
What it means
fetchJsonWithResponse performs an HTTP request expecting JSON and throws a RequestFailedError (an OError subclass carrying the url, opts, response and body) whenever response.ok is false (status outside 200-299). The message is generic 'request failed'; the actual status, URL and response body are attached as properties/info on the error object. JSON parsing failures after a 2xx response throw a different error, so this error specifically means the server returned a failure status.
Source
Thrown at libraries/fetch-utils/index.js:39
* @param {string | URL} url - request URL
* @param {any} [opts] - fetch options
* @return {Promise<any>} the parsed JSON response
* @throws {RequestFailedError} if the response has a failure status code
*/
async function fetchJson(url, opts = {}) {
const { json } = await fetchJsonWithResponse(url, opts)
return json
}
async function fetchJsonWithResponse(url, opts = {}) {
const { fetchOpts, detachSignal } = parseOpts(opts, url)
fetchOpts.headers = fetchOpts.headers ?? {}
fetchOpts.headers.Accept = fetchOpts.headers.Accept ?? 'application/json'
const response = await performRequest(url, fetchOpts, detachSignal)
if (!response.ok) {
const body = await maybeGetResponseBody(response)
throw new RequestFailedError(url, opts, response, body)
}
const json = await response.json()
return { json, response }
}
/**
* Make a request and return a stream.
*
* If the response body is destroyed, the request is aborted.
*
* @param {string | URL} url - request URL
* @param {any} [opts] - fetch options
* @return {Promise<Readable>}
* @throws {RequestFailedError} if the response has a failure status code
*/
async function fetchStream(url, opts = {}) {
const { stream } = await fetchStreamWithResponse(url, opts)View on GitHub (pinned to 28ad3b03b7)
Solutions
- Inspect err.response.status, err.response.body and err.info (OError info) to identify the status and downstream message.
- Verify the URL/route and service hostname/port in configuration.
- Check auth headers/options (opts.headers) and credentials validity if status is 401/403.
- If the status is 5xx or 429, retry with backoff; if it is 4xx, fix the request rather than retrying.
- Check health/logs of the downstream service if 5xx persists.
Example fix
// before
const { json } = await fetchJsonWithResponse(url) // throws on 404
// after
try {
const { json } = await fetchJsonWithResponse(url)
} catch (err) {
if (err instanceof RequestFailedError && err.response.status === 404) {
return null // treat as missing
}
throw err
} Defensive patterns
Strategy: try-catch
Validate before calling
const url = new URL(path, baseUrl)
if (!/^https?:$/.test(url.protocol)) throw new Error(`bad service URL: ${url}`)
// ensure required auth headers present before the call
if (opts.headers?.Authorization == null && requiresAuth) throw new Error('missing Authorization header') Type guard
function isRequestFailedError(err) {
return err instanceof RequestFailedError
} Try / catch
try {
const { json, response } = await fetchJsonWithResponse(url, opts)
} catch (err) {
if (err instanceof RequestFailedError) {
const { status } = err.response
if (status >= 500 || status === 429) {
return retryWithBackoff(() => fetchJsonWithResponse(url, opts))
}
if (status === 404) return null
logger.warn({ url, status, body: err.response.body }, 'request failed')
}
throw err
} Prevention
- Always catch RequestFailedError and branch on err.response.status instead of message text.
- Retry only 5xx/429 (and network errors); never blindly retry 4xx.
- Include the URL and status in your own logs via the error's attached response/body.
- Centralize service-to-service calls in one helper that applies timeout, retry, and error-mapping policy.
When it happens
Trigger: Calling fetchJsonWithResponse(url, opts) (or the makeRequest-style wrappers) and the remote service responds 4xx/5xx — e.g. a 404 from a wrong route, 401/403 from bad auth headers, 429 rate limiting, or a 500 from the downstream service.
Common situations: A dependency service is down or erroring (502/503 from a proxy); wrong base URL or port in service settings; expired/missing auth credentials causing 401; the requested entity was deleted elsewhere giving 404; load-shedding returning 429 under heavy traffic.
Understand the failure class
Background: 'Something went wrong' / 'Request failed (500)' / 'HTTP error! status: 404' — what failed HTTP requests actually mean and how to find the real cause — this error's family across 28 libraries.
Related errors
- Failed to fetch ${url}: ${res.status} ${res.statusText}
- ${serviceName} server not available. Please try again later.
- error accessing web API
- failed to flush project ${projectId}
- file too big
AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03).
Data as JSON: /api/errors/63653eecce766c03.
Report an issue: GitHub.