encode/httpx · error · RemoteProtocolError
Invalid URL in location header: {exc}.
Error message
Invalid URL in location header: {exc}. What it means
Raised as httpx.RemoteProtocolError while following a redirect when the response's 'Location' header cannot be parsed by httpx.URL (which raises InvalidURL). _redirect_url wraps that as a remote protocol violation because the server returned an unusable redirect target.
Source
Thrown at httpx/_client.py:526
method = "GET"
# If a POST is responded to with a 301, turn it into a GET.
# This bizarre behaviour is explained in 'requests' issue 1704.
if response.status_code == codes.MOVED_PERMANENTLY and method == "POST":
method = "GET"
return method
def _redirect_url(self, request: Request, response: Response) -> URL:
"""
Return the URL for the redirect to follow.
"""
location = response.headers["Location"]
try:
url = URL(location)
except InvalidURL as exc:
raise RemoteProtocolError(
f"Invalid URL in location header: {exc}.", request=request
) from None
# Handle malformed 'Location' headers that are "absolute" form, have no host.
# See: https://github.com/encode/httpx/issues/771
if url.scheme and not url.host:
url = url.copy_with(host=request.url.host)
# Facilitate relative 'Location' headers, as allowed by RFC 7231.
# (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource')
if url.is_relative_url:
url = request.url.join(url)
# Attach previous fragment if needed (RFC 7231 7.1.2)
if request.url.fragment and not url.fragment:
url = url.copy_with(fragment=request.url.fragment)
return urlView on GitHub (pinned to b5addb64f0)
Solutions
- Send the request with follow_redirects=False and inspect response.headers['Location'] manually.
- Fix the server to emit a valid, absolute or proper relative Location URL.
- Catch httpx.RemoteProtocolError and retry against a known-good URL.
Example fix
// before
client.get(url, follow_redirects=True)
// after
r = client.get(url, follow_redirects=False)
location = r.headers.get("Location")
# validate/sanitize before re-requesting Defensive patterns
Strategy: validation
Validate before calling
import httpx
probe = client.get(url, follow_redirects=False)
if probe.is_redirect:
loc = probe.headers.get("Location", "")
try:
httpx.URL(loc)
except httpx.InvalidURL:
loc = None # malformed; do not auto-follow
# only follow when loc is parseable Type guard
import httpx
def location_is_valid(response: httpx.Response) -> bool:
if not response.is_redirect:
return True
try:
httpx.URL(response.headers["Location"])
return True
except (KeyError, httpx.InvalidURL):
return False Try / catch
try:
resp = client.get(url, follow_redirects=True)
except httpx.RemoteProtocolError as exc:
if "Invalid URL in location header" in str(exc):
# server returned a malformed redirect; fetch without following
resp = client.get(url, follow_redirects=False)
else:
raise Prevention
- Use follow_redirects=False when you don't trust the server's redirect targets.
- Validate Location headers from untrusted origins before following.
- Catch httpx.RemoteProtocolError around redirect-following requests.
When it happens
Trigger: A 3xx response with follow_redirects=True whose Location header is malformed (e.g. contains illegal/control characters, an unparseable string), so URL(location) raises InvalidURL inside _redirect_url.
Common situations: Buggy servers/proxies emitting broken Location headers; header injection attempts; misconfigured load balancers returning garbage redirect targets.
Related errors
- Malformed Digest WWW-Authenticate header
- Unexpected qop value "{qop!r}" in digest auth
- Exceeded maximum allowed redirects.
- URL too long
- Invalid non-printable ASCII character in URL, {char!r} at po
AI-assisted analysis of encode/httpx@b5addb64f0 (2026-08-04).
Data as JSON: /data/errors/f9c7760d26586aa9.json.
Report an issue: GitHub.