Proxy error codes: a reference for HTTP, curl, Python, Node and Chrome
Proxy error codes in one list: 407, 429, 502, 503 and 504 from the proxy or the site, curl exit codes, Python, Node and Chrome errors, and what to check first.
Proxy error codes come from two places: the proxy, when it refuses to connect you or cannot reach the site, and the website, answering through the proxy. A 407 is always the proxy. A 429, 403, 502 or 503 can be either. Find out which side sent it first, then use the tables below for the message your tool printed.
Each row gives a one-line meaning, the first thing to check, and where to read more. Every message quoted was reproduced against local test proxies with curl 8.5, Python requests 2.34, Node.js 22 with undici 8.11 and axios, and Chrome for Testing 153. Wording drifts between versions, so match on the key words.
Did the proxy or the website send the error?
For an https site, your client first asks the proxy to open a CONNECT tunnel. The proxy answers that itself: 200 for "tunnel open", or an error. Only after a 200 does the website say anything. So:
- An error on the CONNECT came from the proxy. The website never saw you.
- An error after a successful tunnel came from the website, through the proxy.
curl can print both answers side by side:
curl -s -o /dev/null -x "http://USERNAME:PASSWORD@HOST:PORT" \
-w 'proxy said %{http_connect}, site said %{http_code}\n' \
https://api.ipify.org
In our tests, a proxy refusing the tunnel printed proxy said 429, site said 000. A site rate limiting through a working tunnel printed proxy said 200, site said 429. Your code shows the same split in its own way:
| Tool | Proxy refused the tunnel | Site answered with an error |
|---|---|---|
| curl | Exit 56, CONNECT tunnel failed, response 429 |
Exit 0, status in %{http_code} |
| Python requests | ProxyError with Tunnel connection failed: 429 Too Many Requests inside |
A normal response, r.status_code == 429 |
| Node.js undici | TypeError: fetch failed, and two causes deep Proxy response (429) !== 200 when HTTP Tunneling |
A normal response, res.status === 429 |
| Chrome | net::ERR_TUNNEL_CONNECTION_FAILED |
The site's own error page |
One catch: for plain http:// URLs there is no tunnel, and the proxy's error comes back as an ordinary response. requests returned a proxy's 407 as r.status_code == 407 with no exception. Test with an https:// URL when you want the two sides kept apart.
HTTP proxy errors: 400, 403, 407, 429, 502, 503, 504
| Code | Sent by the proxy, it usually means | Sent by the site, it usually means | Check first | Read more |
|---|---|---|---|---|
| 400 | It could not parse what your client sent: a malformed proxy string or the wrong protocol | Your request itself is malformed | The proxy string and scheme | Proxy formats |
| 403 | It will not carry this request: an inactive service or a refused destination | The site refuses the exit IP or your behaviour | The service status, then the target | Getting blocked |
| 407 | It wants a login and did not accept yours | (Not sent by sites; theirs is 401) | Username and password from the service page | Fix 407 |
| 429 | A limit on the proxy side, if your provider sets one | The site is rate limiting you | Which side sent it, then your request rate | Fix 429 |
| 502 | It could not reach the site: bad hostname, refused connection | The site's own gateway failed | Try https://api.ipify.org through the same proxy |
Timeouts |
| 503 | It is temporarily unable to serve you | The site is overloaded, or its bot protection is answering | Retry later, with backoff | Retries |
| 504 | The site did not answer the proxy in time | The site's upstream timed out | Whether the site loads directly | Timeouts |
We reproduced the proxy-side column for 403, 407, 429, 502 and 503 by making a test proxy answer CONNECT with each status. A mistyped site name through a working proxy came back as a 502 from the proxy, because the proxy does the DNS lookup.
curl proxy errors by exit code
| Exit | Message we saw | Meaning | Check first |
|---|---|---|---|
| 5 | Could not resolve proxy: HOST |
The proxy hostname does not resolve | Typo in HOST, or your DNS |
| 5 | Unsupported proxy syntax in '...': Port number was not a decimal number between 0 and 65535 |
curl could not read the proxy string | Symbols in the password, or a colon-separated line |
| 7 | Failed to connect to HOST port PORT after 0 ms: Couldn't connect to server |
Nothing accepted the connection | HOST and PORT, and that the service is active |
| 7 | Unsupported proxy scheme for 'ftp://...' |
A scheme curl does not support for proxies | Use http:// |
| 28 | Failed to connect to HOST port PORT after 3006 ms: Timeout was reached |
Nothing answered at all | A firewall on your network |
| 28 | Connection timed out after 4005 milliseconds |
Connected, but the tunnel or handshake never finished | The proxy or the site, see the timeouts post |
| 28 | Operation timed out after 5006 milliseconds with 0 bytes received |
The tunnel is up and the site is silent | The site, or a slow exit |
| 35 | OpenSSL/3.0.13: error:0A00010B:SSL routines::wrong version number |
TLS spoken to something that is not TLS | https:// written where http:// belongs, or the wrong port |
| 56 | CONNECT tunnel failed, response 407 (or 403, 429, 502, 503) |
The proxy refused the tunnel with that status | The HTTP table above |
| 56 | Recv failure: Connection reset by peer |
The connection was cut | Retry, then try another network |
| 56 | Proxy CONNECT aborted |
The proxy closed without answering | Retry, then check the service |
| 60 | SSL certificate problem: self-signed certificate |
The site's certificate failed verification | The TLS section below |
| 97 | Received invalid version in initial SOCKS5 response. |
socks5:// used against an HTTP proxy |
Use http://, or set that proxy to SOCKS5 in the dashboard |
The millisecond figures are from our runs and will differ on yours. Note that 28 appears three times: the words after the number tell you which stage timed out, and proxy timeout errors shows how to split the time with curl -w.
Python requests proxy errors
| Exception | Inside the message | Meaning |
|---|---|---|
ProxyError |
NewConnectionError ... [Errno 111] Connection refused |
Nothing listening at HOST:PORT |
ProxyError |
NameResolutionError ... Failed to resolve |
The proxy hostname does not resolve |
ProxyError |
ConnectTimeoutError ... timed out |
The proxy never answered the connection |
ProxyError |
OSError('Tunnel connection failed: 407 Proxy Authentication Required') |
The proxy refused the tunnel; the number is its status |
ProxyError |
Your proxy appears to only use HTTP and not HTTPS |
The proxy URL starts with https://; use http:// |
ReadTimeout |
Read timed out. |
Connected, then no answer in time |
ConnectionError |
ConnectionResetError(104, 'Connection reset by peer') |
The connection was cut |
ConnectionError |
RemoteDisconnected('Remote end closed connection without response') |
The proxy closed without answering |
SSLError |
[SSL: WRONG_VERSION_NUMBER] wrong version number |
TLS spoken to a non-TLS port |
SSLError |
CERTIFICATE_VERIFY_FAILED |
The site's certificate failed verification |
InvalidURL / InvalidProxyURL |
Failed to parse / It is malformed |
The proxy string is not a URL requests can read |
The trap in this table: with a proxy set, a timeout reaching the proxy arrives as ProxyError, not as ConnectTimeout. An except requests.ConnectTimeout never sees it. Catch ProxyError too, and read the part after "Caused by".
Node.js proxy errors: ECONNREFUSED, ECONNRESET, ETIMEDOUT
With undici's fetch, every network failure is TypeError: fetch failed. The real reason is in error.cause, sometimes one level further down, so log the chain:
function rootCause(error) {
while (error.cause) error = error.cause;
return typeof error.code === 'string' ? `${error.code}: ${error.message}` : error.message;
}
| Code or message at the bottom of the chain | Meaning |
|---|---|
ECONNREFUSED: connect ECONNREFUSED HOST:PORT |
Nothing listening at the proxy address |
ENOTFOUND: getaddrinfo ENOTFOUND HOST |
The proxy hostname does not resolve |
UND_ERR_CONNECT_TIMEOUT: Connect Timeout Error (attempted address: ...) |
No answer in time, reaching the proxy or opening the tunnel |
UND_ERR_ABORTED: Proxy response (407) !== 200 when HTTP Tunneling |
The proxy refused the tunnel; the number is its status |
UND_ERR_SOCKET: other side closed, under UND_ERR_PRX_CONN: Proxy Connection failed |
The proxy closed without answering |
TimeoutError: The operation was aborted due to timeout |
Your own AbortSignal.timeout fired first |
ECONNRESET: read ECONNRESET |
The connection was cut |
ERR_SSL_WRONG_VERSION_NUMBER |
TLS spoken to a non-TLS port, often an https:// proxy URL |
DEPTH_ZERO_SELF_SIGNED_CERT, ERR_TLS_CERT_ALTNAME_INVALID |
The site's certificate failed verification |
axios with https-proxy-agent gave ECONNREFUSED and ECONNRESET as above, AxiosError: Request failed with status code 407 for a refused login, and connect ETIMEDOUT for a proxy that never answered, after more than two minutes of the operating system's own limit. Set a timeout of your own; the Node.js and axios guides show where.
Chrome net::ERR_ proxy codes
| Code | Meaning |
|---|---|
ERR_PROXY_CONNECTION_FAILED |
Chrome could not reach the proxy: wrong host or port, or a forgotten system proxy |
ERR_TUNNEL_CONNECTION_FAILED |
The proxy refused or could not open the tunnel, including a failed login |
ERR_NO_SUPPORTED_PROXIES |
A login inside --proxy-server, or an unknown scheme |
ERR_PROXY_AUTH_UNSUPPORTED |
The proxy asked for a login method Chrome does not support |
ERR_SOCKS_CONNECTION_FAILED |
socks5:// pointed at an HTTP proxy |
Each of these, the causes we reproduced and where Chrome hides the setting responsible are in Chrome proxy errors.
Certificate errors through a proxy
A CONNECT tunnel passes encrypted bytes through unread, and your client checks the site's certificate end to end. A certificate error therefore means the far end of the tunnel did not present a certificate your client trusts for that name. Check the hostname and port. If every site fails the same way, something on your own network, such as security software or an office gateway, may be inspecting TLS. Turn verification off only for a local test you control.
What do failed requests cost?
That depends on the provider, and it is worth knowing before you write a retry loop. On ours, the honesty page puts it like this: "Connection failures (timeouts, resets, and errors from our own gateway such as a 407 or a 502) are billed at zero and still shown, marked free." Anything the site sends back, a 429 or a 5xx page included, is traffic, so retrying one costs the bytes of that response, usually a small amount. A retry also costs time, and retrying without burning bandwidth covers which errors deserve one.
Quick answers
Which proxy error codes mean my login is wrong? 407 from the proxy, which shows up as curl exit 56 with "response 407", a requests ProxyError mentioning 407, or undici's "Proxy response (407)". In Chrome it becomes ERR_TUNNEL_CONNECTION_FAILED.
Is a 502 my proxy's fault? Not necessarily. A 502 from the proxy usually means it could not reach the site. If https://api.ipify.org works through the same proxy, look at the target.
Why does requests raise ProxyError for a timeout? Because the failure happened while connecting to the proxy. The underlying ConnectTimeoutError is in the message.
Next step
Keep this page open next to your logs, and when an error is not on it, paste it into Discord with the tool, its version and the full message, password removed. If you are still choosing a plan, the pricing page lists every product, and a small top-up is enough to run each check on this page against your own target.