BerriAI/litellm · error · SSRFError
Redirect response has no Location header
Error message
Redirect response has no Location header
What it means
Raised by _extract_redirect_url during litellm's SSRF-protected fetch when a response is classified as a redirect (response.is_redirect) but its Location header is missing, empty, or not a string. RFC-compliant 3xx responses must carry Location, so this indicates a malformed/broken server or an HTTP client edge case, and litellm fails closed rather than guessing the next hop.
Source
Thrown at litellm/litellm_core_utils/url_utils.py:370
expected_host: Final = _normalize_host(expected.hostname or "")
if not candidate_host or candidate_host != expected_host:
raise SSRFError("Origin mismatch on host")
default_port: Final = 443 if candidate.scheme == "https" else 80
candidate_port: Final = candidate.port if candidate.port is not None else default_port
expected_port: Final = expected.port if expected.port is not None else default_port
if candidate_port != expected_port:
raise SSRFError("Origin mismatch on port")
_MAX_REDIRECTS: Final = 10
def _extract_redirect_url(response: Any, request_url: str) -> str:
"""Extract and resolve the redirect target from a response's Location header."""
location: Final = response.headers.get("location")
if not isinstance(location, str) or not location:
raise SSRFError("Redirect response has no Location header")
# Resolve relative URLs against the request URL
return str(httpx.URL(request_url).join(location))
def safe_get(client: Any, url: str, **kwargs: Any) -> Any:
"""
Fetch a user-supplied URL with SSRF protection on every redirect hop.
Validates the initial URL and each redirect target before making the
request. No DNS rebinding (resolve-and-rewrite). No redirect bypass
(each hop validated). No breaking change for legitimate CDN redirects.
When ``litellm.user_url_validation`` is False, validation is bypassed
and this function delegates to ``client.get(url, follow_redirects=True)``.
Args:
client: An httpx.Client (sync).
url: The user-supplied URL.View on GitHub (pinned to 6c2dcb801b)
Solutions
- Reproduce outside the proxy (curl -i) and inspect the 3xx response headers to confirm Location is absent/empty.
- Fix the origin server to send a valid Location header on redirect responses.
- If the status code was wrong (server meant 200), fix the server's status handling.
- As a workaround, request the final intended URL directly instead of following the broken redirect.
Example fix
# server before (Flask)
return "", 302 # no Location header
# after
from flask import redirect
return redirect("https://api.example.com/v1/file", code=302) Defensive patterns
Strategy: try-catch
Validate before calling
def redirect_has_location(response) -> bool:
if not response.is_redirect:
return True
loc = response.headers.get("location")
return isinstance(loc, str) and bool(loc) Try / catch
from litellm.litellm_core_utils.url_utils import SSRFError
try:
resp = safe_get(client, url)
except SSRFError as e:
if "no Location header" in str(e):
return bad_gateway("upstream sent a malformed redirect")
raise Prevention
- Always set Location on 3xx responses in your servers.
- Check proxies/middleware are not stripping Location.
- Return 502-style errors for malformed upstream redirects instead of retrying.
When it happens
Trigger: safe_get on a URL whose server returns a 301/302/307/308 with no Location header, an empty Location, or a non-string header value — e.g. hand-rolled test servers, misconfigured proxies stripping Location, or custom HTTP stacks returning header objects httpx treats as non-str.
Common situations: Test/mock servers returning status 302 without Location; reverse proxies (or security middleware) stripping redirect headers; buggy backend frameworks emitting redirect status codes by mistake; health checks that use 302 semantics without a target.
Related errors
- Too many redirects
- URL scheme is not allowed
- Origin mismatch on scheme
- Origin mismatch on host
- Origin mismatch on port
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/88d476c4d8523514.
Report an issue: GitHub.