psf/requests · error · HTTPError
{self.status_code} Client Error: {reason} for url: {self.url
Error message
{self.status_code} Client Error: {reason} for url: {self.url} What it means
Raised by Response.raise_for_status() in src/requests/models.py when the response status code is in the 4xx range (400 <= status_code < 500). Requests wraps the status, the server-supplied reason phrase (decoded utf-8, falling back to iso-8859-1), and the final URL into a requests.exceptions.HTTPError so callers can turn HTTP-level failures into Python exceptions instead of silently inspecting status codes.
Source
Thrown at src/requests/models.py:1171
try:
reason = self.reason.decode("utf-8")
except UnicodeDecodeError:
reason = self.reason.decode("iso-8859-1")
else:
reason = self.reason
if 400 <= self.status_code < 500:
http_error_msg = (
f"{self.status_code} Client Error: {reason} for url: {self.url}"
)
elif 500 <= self.status_code < 600:
http_error_msg = (
f"{self.status_code} Server Error: {reason} for url: {self.url}"
)
if http_error_msg:
raise HTTPError(http_error_msg, response=self)
def close(self) -> None:
"""Releases the connection back to the pool. Once this method has been
called the underlying ``raw`` object must not be accessed again.
*Note: Should not normally need to be called explicitly.*
"""
if not self._content_consumed:
self.raw.close()
release_conn = getattr(self.raw, "release_conn", None)
if release_conn is not None:
release_conn()
View on GitHub ↗ (pinned to 414f0513c3)
Solutions
- Inspect the failing response before raising: check response.status_code and response.text/response.json() for the server's error detail.
- Fix the request per status: refresh/attach credentials for 401/403, correct the URL or resource ID for 404, validate the payload for 400/422.
- For 429, honor the Retry-After header or add backoff (e.g. urllib3 Retry with status_forcelist).
- Wrap the call in try/except requests.exceptions.HTTPError and use err.response for structured handling.
Example fix
# before
resp = requests.get(url)
resp.raise_for_status()
data = resp.json()
# after
resp = requests.get(url, headers={"Authorization": f"Bearer {token}"})
try:
resp.raise_for_status()
except requests.HTTPError as err:
print(err.response.status_code, err.response.text)
raise
data = resp.json() Defensive patterns
Strategy: try-catch
Type guard
def is_client_error(resp):
return 400 <= resp.status_code < 500 Try / catch
try:
resp = requests.get(url)
resp.raise_for_status()
except requests.exceptions.HTTPError as e:
if e.response is not None and 400 <= e.response.status_code < 500:
handle_client_error(e.response) Prevention
- Only call raise_for_status() when you want exceptions; otherwise branch on resp.status_code or resp.ok
- Check resp.ok before consuming the body
- Handle 401/403/404 explicitly since they indicate caller-side problems (auth, permissions, wrong URL) that retries won't fix
- Access e.response inside the handler to log status and body for diagnosis
When it happens
Trigger: Calling response.raise_for_status() after any requests.get/post/etc. that returned 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 429 Too Many Requests, or any other 4xx. It is never raised automatically — only when raise_for_status() (or code that calls it, e.g. many API client wrappers) is invoked.
Common situations: Missing or expired API keys/tokens (401/403), wrong endpoint paths or IDs (404), malformed JSON bodies or missing required parameters (400/422), rate limiting (429), and redirects landing on auth walls. The URL in the message reflects the final URL after redirects, which often reveals the real problem.
Related errors
- {self.status_code} Server Error: {reason} for url: {self.url
- Missing dependencies for SOCKS support.
- Please check proxy URL. It is malformed and could be missing
AI-assisted analysis of psf/requests@414f0513c3 (2026-07-31).
Data as JSON: /data/errors/28027f65d3a4d5fe.json.
Report an issue: GitHub ↗.