{"record":{"id":"ab65f85997d5d9d7","repo":"crewAIInc/crewAI","slug":"too-many-redirects-while-fetching-url-url","errorCode":null,"errorMessage":"Too many redirects while fetching URL: {url}","messagePattern":"Too many redirects while fetching URL: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"lib/crewai-tools/src/crewai_tools/security/safe_requests.py","lineNumber":78,"sourceCode":"    current_url = validate_url(url)\n    request_kwargs = {**kwargs, \"allow_redirects\": False}\n    timeout = request_kwargs.pop(\"timeout\", 30)\n    history: list[requests.Response] = []\n    redirects_followed = 0\n\n    try:\n        while True:\n            response = requests.get(current_url, timeout=timeout, **request_kwargs)\n            if (\n                response.status_code not in _REDIRECT_STATUS_CODES\n                or \"Location\" not in response.headers\n            ):\n                response.history = history\n                return response\n\n            if redirects_followed >= max_redirects:\n                response.close()\n                raise ValueError(f\"Too many redirects while fetching URL: {url}\")\n\n            location = response.headers.get(\"Location\")\n            if not location:\n                response.history = history\n                return response\n\n            try:\n                redirect_url = validate_url(urljoin(response.url, location))\n            except ValueError:\n                response.close()\n                raise\n\n            if not _same_origin(current_url, redirect_url):\n                request_kwargs = _strip_cross_origin_credentials(request_kwargs)\n\n            history.append(response)\n            current_url = redirect_url\n            redirects_followed += 1","sourceCodeStart":60,"sourceCodeEnd":96,"githubUrl":"https://github.com/crewAIInc/crewAI/blob/754d7323beb2fd042e33444a115ea2d5a47193f0/lib/crewai-tools/src/crewai_tools/security/safe_requests.py#L60-L96","documentation":"safe_get() in crewai_tools follows redirects manually so each hop can be re-validated for SSRF. Once the number of followed redirects reaches max_redirects and the response is still a redirect (status in _REDIRECT_STATUS_CODES with a Location header), this ValueError is raised and the response is closed. It is a circuit breaker against redirect loops and chains that are too long.","triggerScenarios":"Calling safe_get()/fetch_url_body() with default max_redirects on a URL whose server redirects in a cycle (A->B->A), a chain longer than the limit, or a server that always answers 301/302 with a new Location regardless of client behavior.","commonSituations":"Misconfigured web servers with rewrite loops; CDN/auth layers that append tokens and bounce repeatedly; picking up shortener chains that nest several levels deep; lowering max_redirects below the chain length of a legitimate site.","solutions":["Raise max_redirects in the safe_get()/fetch_url_body() call if the chain is legitimate but long.","curl -sIL <url> (or a requests session with allow_redirects) to trace the hop chain and find where the loop occurs.","Fix or report the redirect loop on the originating server (commonly an http<->https or trailing-slash rewrite loop).","Use the final URL from a manual trace and request it directly to skip the chain."],"exampleFix":"// before\nresp = safe_get(url)  # default max_redirects\n\n// after\nresp = safe_get(url, max_redirects=20)","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    resp = safe_get(url)\nexcept ValueError as e:\n    if \"Too many redirects\" in str(e):\n        resp = safe_get(url, max_redirects=25)  # one bounded retry with a higher cap\n    else:\n        raise","preventionTips":["Pass an explicit, generous max_redirects when fetching arbitrary web content.","Trace unfamiliar URLs with curl -sIL once and store the final destination for reuse.","Remember every redirect hop is re-validated for SSRF — chains through internal IPs will fail differently; don't conflate the two errors."],"tags":["http","redirects","network","ssrf"],"backgroundTag":null,"analyzedSha":"754d7323beb2fd042e33444a115ea2d5a47193f0","analyzedAt":"2026-08-15T04:06:56.746Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}