{"id":"f9c7760d26586aa9","repo":"encode/httpx","slug":"invalid-url-in-location-header-exc","errorCode":null,"errorMessage":"Invalid URL in location header: {exc}.","messagePattern":"Invalid URL in location header: (.+?)\\.","errorType":"exception","errorClass":"RemoteProtocolError","httpStatus":null,"severity":"error","filePath":"httpx/_client.py","lineNumber":526,"sourceCode":"            method = \"GET\"\n\n        # If a POST is responded to with a 301, turn it into a GET.\n        # This bizarre behaviour is explained in 'requests' issue 1704.\n        if response.status_code == codes.MOVED_PERMANENTLY and method == \"POST\":\n            method = \"GET\"\n\n        return method\n\n    def _redirect_url(self, request: Request, response: Response) -> URL:\n        \"\"\"\n        Return the URL for the redirect to follow.\n        \"\"\"\n        location = response.headers[\"Location\"]\n\n        try:\n            url = URL(location)\n        except InvalidURL as exc:\n            raise RemoteProtocolError(\n                f\"Invalid URL in location header: {exc}.\", request=request\n            ) from None\n\n        # Handle malformed 'Location' headers that are \"absolute\" form, have no host.\n        # See: https://github.com/encode/httpx/issues/771\n        if url.scheme and not url.host:\n            url = url.copy_with(host=request.url.host)\n\n        # Facilitate relative 'Location' headers, as allowed by RFC 7231.\n        # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource')\n        if url.is_relative_url:\n            url = request.url.join(url)\n\n        # Attach previous fragment if needed (RFC 7231 7.1.2)\n        if request.url.fragment and not url.fragment:\n            url = url.copy_with(fragment=request.url.fragment)\n\n        return url","sourceCodeStart":508,"sourceCodeEnd":544,"githubUrl":"https://github.com/encode/httpx/blob/b5addb64f0161ff6bfe94c124ef76f6a1fba5254/httpx/_client.py#L508-L544","documentation":"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.","triggerScenarios":"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.","commonSituations":"Buggy servers/proxies emitting broken Location headers; header injection attempts; misconfigured load balancers returning garbage redirect targets.","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."],"exampleFix":"// before\nclient.get(url, follow_redirects=True)\n// after\nr = client.get(url, follow_redirects=False)\nlocation = r.headers.get(\"Location\")\n# validate/sanitize before re-requesting","handlingStrategy":"validation","validationCode":"import httpx\nprobe = client.get(url, follow_redirects=False)\nif probe.is_redirect:\n    loc = probe.headers.get(\"Location\", \"\")\n    try:\n        httpx.URL(loc)\n    except httpx.InvalidURL:\n        loc = None  # malformed; do not auto-follow\n# only follow when loc is parseable","typeGuard":"import httpx\n\ndef location_is_valid(response: httpx.Response) -> bool:\n    if not response.is_redirect:\n        return True\n    try:\n        httpx.URL(response.headers[\"Location\"])\n        return True\n    except (KeyError, httpx.InvalidURL):\n        return False","tryCatchPattern":"try:\n    resp = client.get(url, follow_redirects=True)\nexcept httpx.RemoteProtocolError as exc:\n    if \"Invalid URL in location header\" in str(exc):\n        # server returned a malformed redirect; fetch without following\n        resp = client.get(url, follow_redirects=False)\n    else:\n        raise","preventionTips":["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."],"tags":["redirects","protocol","url"],"analyzedSha":"b5addb64f0161ff6bfe94c124ef76f6a1fba5254","analyzedAt":"2026-08-04T19:32:56.768Z","schemaVersion":2}