pypa/pip · error · NetworkConnectionError
Client Error: for url
Error message
{resp.status_code} Client Error: {reason} for url: {resp.url} What it means
Raised as NetworkConnectionError by raise_for_status when an HTTP response carries a 4xx (Client Error) or 5xx (Server Error) status code. The message format is '{status_code} Client Error: {reason} for url: {url}' (and the Server Error variant for 5xx). The original requests Response is attached as .response so callers can inspect status, headers, and body.
Solutions
- Verify the package name and the configured index URL (pip config list; pip install -v).
- Provide credentials if the status is 401/403 (auth in URL, keyring, or --index-url with creds).
- Retry on transient 5xx errors; switch to an alternate mirror if persistent.
- Check pip.conf for a stale/mistyped index-url or extra-index-url.
Defensive patterns
Strategy: try-catch
Try / catch
from pip._internal.exceptions import NetworkConnectionError
try:
resp = session.get(url)
raise_for_status(resp)
except NetworkConnectionError as e:
status = e.response.status_code if e.response is not None else None
if status in (401, 403):
# supply credentials and retry
...
elif status and 500 <= status < 600:
# transient server error, retry with backoff
...
else:
raise Prevention
- Validate package names and index URLs before installing.
- Configure authentication for private indexes up front.
- Retry transient 5xx with backoff; switch mirrors on persistent 4xx.
When it happens
Trigger: pip performs an HTTP GET (index simple page, JSON API, file download) and the server replies with 401/403/404/500/502/503 etc.; raise_for_status converts that into an exception.
Common situations: Wrong package name or index URL (404); private index requiring auth (401/403); index server outage or gateway error (500/502/503); rate limiting; expired credentials.
Related errors
- Could not install requirement
- connection-failed
- connection-timeout
- Error reading pylock file
- incomplete-download
AI-assisted analysis of pypa/pip@f399c37189 (2026-08-08).
Data as JSON: /api/errors/81dd61747503ec39.
Report an issue: GitHub.
Appendix: source
Thrown at src/pip/_internal/network/utils.py:71
try:
reason = resp.reason.decode("utf-8")
except UnicodeDecodeError:
reason = resp.reason.decode("iso-8859-1")
else:
reason = resp.reason
if 400 <= resp.status_code < 500:
http_error_msg = (
f"{resp.status_code} Client Error: {reason} for url: {resp.url}"
)
elif 500 <= resp.status_code < 600:
http_error_msg = (
f"{resp.status_code} Server Error: {reason} for url: {resp.url}"
)
if http_error_msg:
raise NetworkConnectionError(http_error_msg, response=resp)
def response_chunks(
response: Response, chunk_size: int = DOWNLOAD_CHUNK_SIZE
) -> Generator[bytes, None, None]:
"""Given a requests Response, provide the data chunks."""
try:
# Special case for urllib3.
for chunk in response.raw.stream(
chunk_size,
# We use decode_content=False here because we don't
# want urllib3 to mess with the raw bytes we get
# from the server. If we decompress inside of
# urllib3 then we cannot verify the checksum
# because the checksum will be of the compressed
# file. This breakage will only occur if the
# server adds a Content-Encoding header, which
# depends on how the server was configured:View on GitHub (pinned to f399c37189)