aio-libs/aiohttp · error · ClientHttpProxyError
ClientHttpProxyError: {message}
Error message
ClientHttpProxyError: {message} What it means
Raised inside _create_proxy_connection when the proxy's response to the CONNECT request has a status other than 200. aiohttp had successfully established a transport to the proxy and issued CONNECT host:port, but the proxy refused to tunnel (401/403/407/502/etc.). The proxy's reason phrase (or the HTTPStatus phrase if reason is missing) is carried as the message, so the failure cause from the proxy is visible.
Source
Thrown at aiohttp/connector.py:1641
# once the response is received and processed allowing
# START_TLS to work on the connection below.
protocol.set_response_params(
read_until_eof=True,
timeout_ceil_threshold=self._timeout_ceil_threshold,
)
resp = await proxy_resp.start(conn)
except BaseException:
proxy_resp.close()
conn.close()
raise
else:
conn._protocol = None
try:
if resp.status != 200:
message = resp.reason
if message is None:
message = HTTPStatus(resp.status).phrase
raise ClientHttpProxyError(
proxy_resp.request_info,
resp.history,
status=resp.status,
message=message,
headers=resp.headers,
)
except BaseException:
# It shouldn't be closed in `finally` because it's fed to
# `loop.start_tls()` and the docs say not to touch it after
# passing there.
transport.close()
raise
return await self._start_tls_connection(
# Access the old transport for the last time before it's
# closed and forgotten forever:
transport,
req=req,View on GitHub (pinned to d041d4d0fd)
Solutions
- Supply proxy credentials via the proxy URL (http://user:pass@proxy:port) or proxy_headers Authorization/Proxy-Authorization.
- Verify the proxy allows CONNECT to the target host and port (proxy ACL).
- Check HTTP_PROXY/HTTPS_PROXY/NO_PROXY env vars for stale or mistyped values.
- Reproduce with curl -x http://proxy:port https://target to confirm the proxy, not aiohttp, is rejecting.
Example fix
# before
await session.get('https://target/', proxy='http://corp-proxy:8080')
# after - add proxy auth
from urllib.parse import quote
proxy = 'http://{}:{}@corp-proxy:8080'.format(quote(user), quote(password))
await session.get('https://target/', proxy=proxy) Defensive patterns
Strategy: try-catch
Validate before calling
from urllib.parse import urlparse, quote
def proxy_with_auth(proxy_url, user, password):
p = urlparse(proxy_url)
userinfo = f'{quote(user, safe="")}:{quote(password, safe="")}@'
return f'{p.scheme}://{userinfo}{p.hostname}:{p.port}'
proxy = proxy_with_auth(base_proxy, user, password) Type guard
null
Try / catch
try:
resp = await session.get(url, proxy=proxy)
except aiohttp.ClientHttpProxyError as exc:
if exc.status in (401, 407):
proxy = refresh_proxy_credentials()
resp = await session.get(url, proxy=proxy)
else:
raise Prevention
- Supply proxy credentials in the proxy URL or via proxy_headers.
- Verify the proxy permits CONNECT to the target host and port.
- Reproduce proxy rejection with curl -x to confirm the proxy, not aiohttp, is denying.
When it happens
Trigger: Proxy requires authentication that was not supplied (407 Proxy Authentication Required); proxy denied by ACL (403); proxy could not reach the upstream (502/504); wrong proxy URL; proxy requires credentials in a different scheme (Basic vs Digest); expired proxy credentials.
Common situations: Corporate proxy credentials rotated; environment HTTP_PROXY/HTTPS_PROXY pointing at the wrong proxy; proxy auth header not set because aiohttp's proxy auth was not configured; proxy blocking the target host by policy.
Related errors
- Cannot connect to host {host}:{port} ssl:{ssl} [{certificate
- Cannot connect to host {host}:{port} ssl:{ssl} [{strerror}]
- No .netrc file found
- No entry for {host!s} found in the `.netrc` file.
- Connection timeout to host {req.url}
AI-assisted analysis of aio-libs/aiohttp@d041d4d0fd (2026-08-11).
Data as JSON: /api/errors/97fc26728e73c2a3.
Report an issue: GitHub.