ProxyError in requests: Unable to Connect to Proxy
The requests library could not get through the proxy: either it did not connect to it, or the proxy refused to open a tunnel to the site. The long error text tells you which one happened.
Updated · Prokso editorial team
- ProxyError means requests did not get through the proxy: it did not connect or did not get a tunnel
- The real cause is in the brackets after Caused by, and the word after 407 or 503 names it exactly
- Set the proxy line with the http:// scheme for both dictionary keys and check the environment variables
What the error means
The message looks like this: HTTPSConnectionPool(host='example.com', port=443): Max retries exceeded with url: / (Caused by ProxyError('Unable to connect to proxy', ...)). The important part is in the brackets after Caused by. The urllib3 library that requests is built on wraps the real cause in a ProxyError, and requests raises it as requests.exceptions.ProxyError.
The words Max retries exceeded do not mean there were many attempts. According to the documentation, requests does not retry failed connections by default, so this text appears after the very first attempt. In the old urllib3 1.26 branch the text was Cannot connect to proxy. instead of Unable to connect to proxy. The meaning is the same.
Inside there is usually one of two variants. NewConnectionError with Connection refused, or ConnectTimeoutError, means the program could not even connect to the proxy. OSError('Tunnel connection failed: 407 NO_USER') means the connection to the proxy exists, but the proxy answered the CONNECT request with something other than 200. The code is followed by the response text, and in Prokso it names the reason: NO_USER, TRAFFIC_EXHAUSTED, THREADS_EXHAUSTED, NO_RAY or NO_HOST_CONNECTION.
Causes
- The wrong host or port. Connection refused or a connect timeout: the line does not say gw.prokso.com, or the port is outside 823, 824 and 10000-20000.
- The username or password was not accepted. Tunnel connection failed: 407 NO_USER means an error in the username or password. If you sign in by IP, your current address is not in the allowed list.
- A plan limit was reached. 407 TRAFFIC_EXHAUSTED: the traffic has run out. 407 THREADS_EXHAUSTED: more than 1000 simultaneous connections are open on the plan.
- No address for the geo, or the site is unreachable. 503 NO_RAY: there is no free IP for the selected country, city or ASN right now. 502 NO_HOST_CONNECTION: the proxy could not connect to the site.
- Special characters in the password are not encoded. Characters such as @, : or # in the username or password break the parsing of the line, and the proxy receives the wrong data.
How to fix it
- Copy the proxy line from the dashboard again and set it for both keys:
proxies={'http': 'http://USERNAME:PASSWORD@gw.prokso.com:823', 'https': 'http://USERNAME:PASSWORD@gw.prokso.com:823'}. The scheme of the proxy itself is http:// here, even when the site uses https://. - If the password contains special characters, encode the username and password with
urllib.parse.quote(PASSWORD, safe='')before putting them into the line. - Read the word after the code in Tunnel connection failed. For NO_USER, check the username and the IP list; for TRAFFIC_EXHAUSTED, top up traffic; for THREADS_EXHAUSTED, reduce the number of threads; for NO_RAY, widen the geo.
- Check the HTTP_PROXY, HTTPS_PROXY and ALL_PROXY environment variables. Requests reads them, and the documentation warns that they can override
session.proxies. It is more reliable to passproxies=to every request. - Set
timeout=(10, 30)and add a retry with a pause for 502 and 503: on port 823 the retry will go through a different IP. A full example is in the Python requests guide, and the general order of troubleshooting is on the troubleshooting page.
How to check that it works
Run requests.get('https://prokso.com/ip', proxies=proxies, timeout=30).json(). If the response shows the IP and country of the proxy rather than yours, the connection works. You can test the same line without code in the proxy checker: if it is fine there, look for the cause in your code or environment variables.
Two-minute diagnosis
First paste the line into the proxy checker. If the proxy works there, the cause is in your app or its settings. If not, test the line from a terminal:
curl -v -x "http://USERNAME:PASSWORD@gw.prokso.com:823" https://api.ipify.org
- A
< HTTP/1.1 407line right afterCONNECTmeans the proxy answered. The name after the code, for exampleNO_USER, points to the cause. - The proxy answered
CONNECTwith 200 and then another code arrived - the proxy works, and that answer came from the website. - No answer at all, only a timeout - the connection never reached the proxy: check the host, port and network.
Setup guides where this error comes up
FAQ
Why does 407 come as a response for an http site and not as an exception?
For http:// addresses, requests does not open a tunnel; it sends the request to the proxy directly. So 407 comes back as an ordinary response.status_code. A CONNECT tunnel is only needed for https://, and there a refusal becomes a ProxyError exception. What the code itself means is explained on the <a href="/en/errors/407-proxy-authentication-required">407 Proxy Authentication Required</a> page.
What if there is a ConnectTimeoutError inside?
The proxy did not respond within the connect timeout. Check the host and port, your network and firewall, and then the <a href="/en/errors/proxy-timeout">proxy timeout</a> page.
Why does the site see my address even though the proxy is set?
Most often the dictionary only has the 'http' key, while the site uses https://. The key matches the scheme of the site, so requests to https:// go directly. Set both keys.
Is it enough to catch only ProxyError?
ProxyError is a subclass of requests.exceptions.ConnectionError. Requests raises SOCKS proxy errors as ConnectionError, so if you work with both protocols, catch ConnectionError.
Other proxy errors
Residential $1.59, mobile $2.50, datacenter $0.65 per GB
Sign up in a minute, get access right after payment.