Errors & retries
When something goes wrong, the proxy answers with a status code before your request reaches the target.
A code from us is not a code from the site you are scraping. A 403 or a CAPTCHA
page is a successful proxy request that the destination refused. Everything below
happens earlier than that.
Every code
Section titled “Every code”| Code | What happened | What to do |
|---|---|---|
400 |
We cannot proxy that address | Send a hostname or public IP |
407 |
We do not recognize your account | Check your balance, then your credentials |
451 |
The domain is blocked | Contact support |
551 |
No exit matched your targeting | Loosen your targeting |
556 |
You are over your request-rate limit | Slow down |
504 552 |
We tried several exits and all of them failed | Retry |
554 557 |
Something failed on our side | Retry |
Codes above 550 are ours. They are not defined in any RFC.
Fix your request
Section titled “Fix your request”400 means the target is not something we proxy. Loopback addresses and
bracketed IPv6 literals are rejected. Send a hostname or a public IPv4 address.
551 means you described a set of exits that is currently empty. Loosen the
narrowest option and try again, in this order:
- ZIP code covers a few thousand households
- ASN cuts you to one carrier
- Device OS has no fallback
- City, then state
Retrying the identical request returns 551 again. Change the targeting instead.
A request that used to work can start returning 551 without your code
changing. Exits join and leave constantly, and a narrow combination that had
coverage an hour ago may have none now.
Fix your account
Section titled “Fix your account”407 usually means an empty balance, not a wrong password. A balance that
reaches zero suspends the account, and a suspended account is no longer
recognized at the proxy. It fails exactly as though the credentials were wrong.
Check in this order:
- Your balance. Usage & statistics or the Bandwidth API.
- Whether options landed on the username. Targeting appends to the
password.
USERNAME-country-US:PASSWORDis an unknown user. - Your source IP, if you use IP whitelisting. A changed egress address fails the same way.
- The password itself.
A sub-account is also suspended when the master account’s balance runs out. If every sub-account fails at once, check the master.
451 carries its reason in the status line, and the body is empty. Clients
expose it as r.reason in Python requests or res.statusText in a browser.
See Acceptable use.
556 is sent about five seconds after the request. A client timeout under
five seconds turns it into a timeout and hides the cause.
504, 552, 554 and 557 are transient. Retry with a backoff, two attempts
rather than ten in a loop.
We retry internally before returning any of them, so your retry sits on top of ours.
If 504 or 552 persists against one target while other targets work, that
target is refusing our exits rather than the network failing. See
Choosing a product.
A failure after the tunnel opens has no status code. Your TLS handshake is
already in flight, and an HTTP status line cannot be written into an encrypted
stream. The connection closes instead, so your client reports ECONNRESET.
Retry it like a 552. Those bytes are not billed.
Reading the code over HTTPS
Section titled “Reading the code over HTTPS”Over CONNECT, curl reports the tunnel result rather than the proxy’s status.
%{http_code} prints 000 and the message is CONNECT tunnel failed. Use -v
to see the real code:
Plain HTTP on the same port returns the code normally.
Retrying in code
Section titled “Retrying in code”import time, requests
RETRY = {504, 552, 554, 557}TERMINAL = {400, 407, 451, 551, 556}
def fetch(url, proxies, attempts=3): for i in range(attempts): try: r = requests.get(url, proxies=proxies, timeout=60) except requests.exceptions.ConnectionError: time.sleep(2 ** i) # tunnel closed mid-request continue if r.status_code in TERMINAL: raise RuntimeError(f"{r.status_code} {r.reason}") if r.status_code in RETRY: time.sleep(2 ** i) continue return r raise RuntimeError("out of attempts")Set a client timeout of at least 60 seconds. We may try several exits before
answering, and a 556 alone takes five.
Retrying a terminal code returns the same code.
Over SOCKS5
Section titled “Over SOCKS5”SOCKS5 has five reply bytes, so several causes share one.
| Reply | Cause |
|---|---|
0x00 |
Success |
0x01 |
Credentials not recognized, or over the request-rate limit |
0x04 |
Something failed on our side |
0x05 |
Blocked domain, or no exit matched your targeting |
0x07 0x08 |
Unsupported command or address type |
0x01 and 0x05 each cover two causes, and one of each pair is worth retrying
while the other is not. Reproduce an ambiguous SOCKS5 failure over HTTP on port
8000 to get a specific code.
Getting help
Section titled “Getting help”Contact support with the timestamp, the entry point you connected to, and the exact targeting options you sent. The destination URL alone is not enough to find a request.
Was this page helpful?
Thanks — that helps us fix it.