{"id":"7305bb3382f5a59c","repo":"encode/httpx","slug":"exceeded-maximum-allowed-redirects","errorCode":null,"errorMessage":"Exceeded maximum allowed redirects.","messagePattern":"Exceeded maximum allowed redirects\\.","errorType":"exception","errorClass":"TooManyRedirects","httpStatus":null,"severity":"error","filePath":"httpx/_client.py","lineNumber":972,"sourceCode":"                    response.read()\n                    request = next_request\n                    history.append(response)\n\n                except BaseException as exc:\n                    response.close()\n                    raise exc\n        finally:\n            auth_flow.close()\n\n    def _send_handling_redirects(\n        self,\n        request: Request,\n        follow_redirects: bool,\n        history: list[Response],\n    ) -> Response:\n        while True:\n            if len(history) > self.max_redirects:\n                raise TooManyRedirects(\n                    \"Exceeded maximum allowed redirects.\", request=request\n                )\n\n            for hook in self._event_hooks[\"request\"]:\n                hook(request)\n\n            response = self._send_single_request(request)\n            try:\n                for hook in self._event_hooks[\"response\"]:\n                    hook(response)\n                response.history = list(history)\n\n                if not response.has_redirect_location:\n                    return response\n\n                request = self._build_redirect_request(request, response)\n                history = history + [response]\n","sourceCodeStart":954,"sourceCodeEnd":990,"githubUrl":"https://github.com/encode/httpx/blob/b5addb64f0161ff6bfe94c124ef76f6a1fba5254/httpx/_client.py#L954-L990","documentation":"Raised as httpx.TooManyRedirects by _send_handling_redirects when len(history) exceeds self.max_redirects (default 20). Each followed 3xx appends to history; once over the cap the redirect chain is aborted.","triggerScenarios":"A request with follow_redirects=True that enters a redirect loop (A->B->A) or a chain longer than max_redirects (default DEFAULT_MAX_REDIRECTS=20).","commonSituations":"Redirect loops caused by http<->https or trailing-slash ping-pong; misconfigured servers; legitimate but very long redirect chains.","solutions":["Raise the cap: httpx.Client(max_redirects=50).","Set follow_redirects=False and follow the final Location yourself once.","Inspect the caught exception's .request/.history to find where the loop starts and fix the server."],"exampleFix":"// before\nclient.get(url, follow_redirects=True)  # TooManyRedirects\n// after\nhttpx.get(url, follow_redirects=True, max_redirects=50)","handlingStrategy":"retry","validationCode":"import httpx\n# validate the redirect cap you intend to use\nassert isinstance(max_redirects, int) and max_redirects > 0\nclient = httpx.Client(follow_redirects=True, max_redirects=max_redirects)","typeGuard":null,"tryCatchPattern":"try:\n    resp = client.get(url, follow_redirects=True)\nexcept httpx.TooManyRedirects as exc:\n    # inspect exc.history to find the loop, then fetch the resolved URL directly\n    last = exc.history[-1]\n    resp = client.get(last.headers.get(\"Location\", url), follow_redirects=False)","preventionTips":["Set max_redirects high enough for legitimate chains.","Use follow_redirects=False for untrusted endpoints and resolve manually.","Log redirect history on failure to detect loops early."],"tags":["redirects","loop","sync"],"analyzedSha":"b5addb64f0161ff6bfe94c124ef76f6a1fba5254","analyzedAt":"2026-08-04T19:32:56.768Z","schemaVersion":2}