Python proxy errors: why the strings you find in search do not match yours
The hard part about Python proxy errors is not the errors but the fact that half the answers in search were written for library versions five years old. The strings changed, the bugs were fixed, the advice stayed. Below is what your version actually says.
The string changed
The most-pasted string of all — “Cannot connect to proxy.” — belongs to urllib3 version 1. Version 2 does not contain it at all: the message is assembled differently there and reads “Unable to connect to proxy”, with no trailing period. If you search the old string and find nothing matching your traceback, that is why.
# Checked on urllib3 2.7.0, requests 2.34.2, aiohttp 3.14.3, httpx 0.28.1
#
# WAS (urllib3 1.x) NOW (urllib3 2.x)
"Cannot connect to proxy." "Unable to connect to proxy"
<- no trailing period
#
# THE HTTP/HTTPS HINT
". Your proxy appears to only use HTTP and not HTTPS, try changing your
proxy URL to be HTTP."
Since 1.26.10 it is added only when the proxy scheme is https.
Before 1.26.10 it was added on a text match against the TLS error, so it
fired even when the proxy was fine. Hence the myth that outlived the bug.
#
# SOCKS WITHOUT THE DEPENDENCY
requests -> InvalidSchema, not ProxyError. Install: pip install requests[socks]
httpx -> a different library: pip install httpx[socks]The myth about the HTTP-versus-HTTPS hint
Next in popularity is the hint “Your proxy appears to only use HTTP and not HTTPS”. It is widely known to lie: it is attached on a text match against the TLS error and shows up even when the proxy is fine. That was true in exactly two releases — 1.26.8 and 1.26.9.
1.26.10 added a scheme check: the hint now appears only if you really are addressing the proxy over https. The corresponding tracker issue was closed back in 2022. So if you are seeing the hint, it is most likely right, and the thing to inspect is the scheme in your connection string rather than dismissing the hint out of habit.
How to read nested exceptions
Exceptions here are nested several layers deep, and the informative one is the innermost, not the outermost. On the outside you usually get requests' ProxyError, under it urllib3's MaxRetryError, under that urllib3's own ProxyError, and at the very bottom the original socket error. The rule is simple: read the traceback from the end, because that is where what actually happened is written — a refused connection, a timeout or a TLS error.
SOCKS fails with the wrong exception
Point requests at a socks5 proxy without the dependency installed and you get InvalidSchema rather than ProxyError — the library is saying it does not understand the scheme, not that the proxy is unreachable. Hence people hunting for proxy problems where a package is missing. It installs as requests[socks]; httpx needs a different library for the same thing, installed as httpx[socks].
Separately: a dead SOCKS proxy in requests arrives as ConnectionError, not ProxyError. So the exception class alone cannot tell “missing dependency”, “proxy is dead” and “proxy refused” apart — you need the text.
Two stale claims about async clients
First: “aiohttp does not support HTTPS proxies”. It does, from Python 3.11 onward — the limitation was in the async transport rather than in the library. Documentation still carries a line about TLS-in-TLS being unavailable, and that line is out of date.
Second: “in httpx, use proxies=”. That parameter is not merely deprecated but removed in 0.28.0 — code using it fails with TypeError. The current name is proxy. Worth knowing too that httpx raises on an authentication refusal only for https targets, where CONNECT is involved; for http targets you get an ordinary response carrying 407.
And what has not changed: aiohttp ignores proxy environment variables by default. Getting it to read them requires trust_env. That is not a bug or a regression but long-standing default behaviour — though it reliably produces the question “why is my HTTP_PROXY ignored”.
How not to hit this again
A habit that saves hours: when searching by error text, look at the date of the answer and the version it was written for, and check any doubtful claim against the source of the version you actually installed. The libraries sit right there in your environment, and searching for the error string finds both where it is raised and the condition under which it is added.
If the error really is the proxy
Separating a client problem from a proxy problem takes one command — and our free tools. Rotating IPv6 from 650 ₽ for 50 threads.
View pricingProxies for this job
Check it with our tools
Read next
- How to use proxies in Python: requests, Scrapy and SeleniumWorking examples for the three most common cases, the difference between socks5 and socks5h, and why IP authentication is easier in a browser.
- Proxy error 407 Proxy Authentication Required: why the proxy rejects your scraper407 comes from the proxy, not the target site. Five causes by frequency, a one-command check, and what to do when your software only accepts ip:port.
- Chrome proxy errors: what each code means, and how −111 differs from −130ERR_TUNNEL_CONNECTION_FAILED and ERR_PROXY_CONNECTION_FAILED sound alike but describe different stages. A table checked against the source, and what Chrome actually does when a proxy fails.
