{"record":{"id":"1c554f437ee15057","repo":"Budibase/budibase","slug":"maximum-redirect-reached","errorCode":null,"errorMessage":"Maximum redirect reached.","messagePattern":"Maximum redirect reached\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"packages/backend-core/src/utils/outboundFetch.ts","lineNumber":236,"sourceCode":"      return response\n    }\n\n    releaseResponseBody(response)\n\n    if (!followRedirects) {\n      throw new Error(\"Redirects are not permitted.\")\n    }\n\n    if (redirects === MAX_REDIRECTS) {\n      break\n    }\n\n    const location = response.headers.get(\"location\")\n    if (!location) {\n      if (returnRedirectWithoutLocation) {\n        return response\n      }\n      throw new Error(\"Maximum redirect reached.\")\n    }\n\n    const redirectUrl = parseUrl(\n      new URL(location, nextUrl).toString()\n    ).toString()\n    nextRequest = nextRequestForRedirect(nextRequest, response.status)\n    if (shouldStripSensitiveHeadersForRedirect(nextUrl, redirectUrl)) {\n      if (rejectCrossOriginRedirects) {\n        throw new Error(\"Redirect to a different origin is not permitted.\")\n      }\n      nextRequest = stripSensitiveHeadersForRedirect(nextRequest)\n    }\n    nextUrl = redirectUrl\n  }\n\n  throw new Error(\"Maximum redirect reached.\")\n}\n","sourceCodeStart":218,"sourceCodeEnd":254,"githubUrl":"https://github.com/Budibase/budibase/blob/a81a902e9a8fe55b467d106765f6638f12e35c49/packages/backend-core/src/utils/outboundFetch.ts#L218-L254","documentation":"When a redirect response (3xx) arrives without a Location header, the library cannot compute the next URL. Unless the caller opted into returnRedirectWithoutLocation, it throws this (misleadingly named) error, since a redirect it cannot follow was received.","triggerScenarios":"Server returns 301/302/303/307/308 with no Location header, followRedirects is true, returnRedirectWithoutLocation is false (default), and the redirect budget hasn't been exhausted (redirects !== MAX_REDIRECTS at the break).","commonSituations":"Misconfigured or broken remote servers emitting bare 3xx responses; middleware/proxies that strip the Location header; custom fetchFn returning hand-crafted response objects lacking headers.get(\"location\").","solutions":["Pass { returnRedirectWithoutLocation: true } if your code can tolerate/handle malformed redirects.","Inspect the offending server's 3xx response (curl -i) and fix it server-side to include Location.","Verify the custom fetchFn returns a faithful Response whose headers include Location."],"exampleFix":"// before\nawait fetchWithBlacklist(url)\n// after\nawait fetchWithBlacklist(url, {}, { returnRedirectWithoutLocation: true })","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  return await fetchWithBlacklist(url, req)\n} catch (err) {\n  if (err instanceof Error && err.message === \"Maximum redirect reached.\") {\n    // a 3xx without Location was received — retry tolerating malformed redirects\n    return fetchWithBlacklist(url, req, { returnRedirectWithoutLocation: true })\n  }\n  throw err\n}","preventionTips":["Set returnRedirectWithoutLocation: true when fetching third-party endpoints you don't control.","Report bare-3xx servers to their owners; they are protocol violations.","Sanity-check custom fetchFn responses preserve headers."],"tags":["http","redirect","fetch","edge-case"],"backgroundTag":"redirect-without-location","analyzedSha":"a81a902e9a8fe55b467d106765f6638f12e35c49","analyzedAt":"2026-08-29T01:03:10.972Z","schemaVersion":2},"datasetVersion":"2026-08-29T02:17:18.158Z"}