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

  1. Inspect err.response.status, err.response.body and err.info (OError info) to identify the status and downstream message.
  2. Verify the URL/route and service hostname/port in configuration.
  3. Check auth headers/options (opts.headers) and credentials validity if status is 401/403.
  4. If the status is 5xx or 429, retry with backoff; if it is 4xx, fix the request rather than retrying.
  5. 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

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


AI-assisted analysis of overleaf/overleaf@28ad3b03b7 (2026-09-03). Data as JSON: /api/errors/63653eecce766c03. Report an issue: GitHub.