{"record":{"id":"f7e11176f50ebf7f","repo":"JuliusBrussee/caveman","slug":"fetch-failed-too-many-redirects","errorCode":null,"errorMessage":"fetch failed: too many redirects","messagePattern":"fetch failed: too many redirects","errorType":"exception","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"packages/cli/src/proxy-fetch.ts","lineNumber":352,"sourceCode":"      headers,\n      body: buffered,\n      signal: request.signal ?? null,\n    };\n    let hop = resolveProxyUrl(current.url, env);\n\n    for (let redirects = 0; ; redirects += 1) {\n      const response = hop ? await sendThroughProxy(current, hop) : await baseFetch(current.url, {\n        method: current.method,\n        headers: current.headers as HeadersInit,\n        body: asBodyInit(current.body),\n        signal: current.signal,\n        redirect: \"manual\",\n      });\n\n      const location = response.headers.get(\"location\");\n      const redirectable = [301, 302, 303, 307, 308].includes(response.status);\n      if (!redirectable || !location || request.redirect === \"manual\") return response;\n      if (redirects >= MAX_REDIRECTS) throw new TypeError(\"fetch failed: too many redirects\");\n      if (request.redirect === \"error\") throw new TypeError(\"fetch failed: unexpected redirect\");\n\n      const next = new URL(location, current.url);\n      const method = nextMethod(response.status, current.method);\n      const bodyDropped = method !== current.method;\n      void response.body?.cancel();\n      current = {\n        method,\n        url: next,\n        headers: redirectedHeaders(current.headers, current.url, next, bodyDropped),\n        body: bodyDropped ? null : current.body,\n        signal: current.signal,\n      };\n      hop = resolveProxyUrl(next, env);\n    }\n  } as typeof fetch;\n}\n","sourceCodeStart":334,"sourceCodeEnd":370,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/5184b3d11ac6a1acb7d44b9bfaa31698157cff97/packages/cli/src/proxy-fetch.ts#L334-L370","documentation":"The proxy-aware fetch follows 3xx redirects automatically (for statuses 301/302/303/307/308 with a Location header) but caps the chain at MAX_REDIRECTS. When the server keeps redirecting past that limit, this TypeError aborts the request.","triggerScenarios":"A fetch through createProxyAwareFetch receives more than MAX_REDIRECTS consecutive redirect responses — typically a redirect loop (A -> B -> A) or an extremely long redirect chain.","commonSituations":"Misconfigured server rewriting http->http or cookie-dependent redirects (redirect requires a session cookie the client isn't sending through the proxy); auth-gated URLs bouncing between login endpoints; proxy intercepting and re-redirecting each hop.","solutions":["Fix the server-side redirect loop (check the Location targets and rewrite rules).","Hit the final target URL directly to confirm the chain length: `curl -IL <url>`.","Ensure cookies/auth headers needed by the redirect target are sent (redirects often drop credentials cross-origin).","Check whether the proxy rewrites or re-redirects responses; bypass the proxy for that host (NO_PROXY).","If the app must follow longer chains, raise MAX_REDIRECTS in proxy-fetch.ts or pass redirect: \"manual\" and handle hops yourself."],"exampleFix":"// before\nawait fetch(\"http://old.example.com/loop\"); // redirects forever\n// after\nconst res = await fetch(\"https://new.example.com/final-target\"); // call the canonical URL directly","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"function isTooManyRedirects(e: unknown): boolean { return e instanceof TypeError && e.message.includes(\"too many redirects\"); }","tryCatchPattern":"try {\n  const res = await fetch(url);\n} catch (e) {\n  if (e instanceof TypeError && e.message.includes(\"too many redirects\")) {\n    console.error(`Redirect loop at ${url}; try the canonical URL or bypass the proxy`);\n  } else throw e;\n}","preventionTips":["Curl -IL your endpoints to confirm sane redirect chains (1 hop max).","Avoid http->https or trailing-slash loops in server config.","Send required cookies/auth headers so authenticated redirects resolve in one hop.","Add hosts with redirect quirks to NO_PROXY if the proxy amplifies loops."],"tags":["network","http","redirect","fetch"],"backgroundTag":"too-many-redirects","analyzedSha":"5184b3d11ac6a1acb7d44b9bfaa31698157cff97","analyzedAt":"2026-08-31T22:10:17.934Z","contentChangedAt":"2026-08-31T22:10:17.934Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}