crewAIInc/crewAI · error · ValueError
Too many redirects while fetching URL: {url}
Error message
Too many redirects while fetching URL: {url} What it means
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.
Source
Thrown at lib/crewai-tools/src/crewai_tools/security/safe_requests.py:78
current_url = validate_url(url)
request_kwargs = {**kwargs, "allow_redirects": False}
timeout = request_kwargs.pop("timeout", 30)
history: list[requests.Response] = []
redirects_followed = 0
try:
while True:
response = requests.get(current_url, timeout=timeout, **request_kwargs)
if (
response.status_code not in _REDIRECT_STATUS_CODES
or "Location" not in response.headers
):
response.history = history
return response
if redirects_followed >= max_redirects:
response.close()
raise ValueError(f"Too many redirects while fetching URL: {url}")
location = response.headers.get("Location")
if not location:
response.history = history
return response
try:
redirect_url = validate_url(urljoin(response.url, location))
except ValueError:
response.close()
raise
if not _same_origin(current_url, redirect_url):
request_kwargs = _strip_cross_origin_credentials(request_kwargs)
history.append(response)
current_url = redirect_url
redirects_followed += 1View on GitHub (pinned to 754d7323be)
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.
Example fix
// before resp = safe_get(url) # default max_redirects // after resp = safe_get(url, max_redirects=20)
Defensive patterns
Strategy: retry
Try / catch
try:
resp = safe_get(url)
except ValueError as e:
if "Too many redirects" in str(e):
resp = safe_get(url, max_redirects=25) # one bounded retry with a higher cap
else:
raise Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Unable to fetch documentation from {docs_url}: {e}
- Error fetching content from URL {url}: {e!s}
- Failed to download PDF from {url}: {e!s}
- Error fetching content from URL {url}: {e!s}
- Error loading webpage {url}: {e!s}
AI-assisted analysis of crewAIInc/crewAI@754d7323be (2026-08-15).
Data as JSON: /api/errors/ab65f85997d5d9d7.
Report an issue: GitHub.