Skip to content
Start free trial

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.

CodeWhat happenedWhat to do
400We cannot proxy that addressSend a hostname or public IP
407We do not recognize your accountCheck your balance, then your credentials
451The domain is blockedContact support
551No exit matched your targetingLoosen your targeting
556You are over your request-rate limitSlow down
504 552We tried several exits and all of them failedRetry
554 557Something failed on our sideRetry

Codes above 550 are ours. They are not defined in any RFC.

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:

  1. ZIP code covers a few thousand households
  2. ASN cuts you to one carrier
  3. Device OS has no fallback
  4. 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.

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:

  1. Your balance. Usage & statistics or the Bandwidth API.
  2. Whether options landed on the username. Targeting appends to the password. USERNAME-country-US:PASSWORD is an unknown user.
  3. Your source IP, if you use IP whitelisting. A changed egress address fails the same way.
  4. 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.

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:

Terminal window
curl -sv -x USERNAME:[email protected]:8000 https://checkip.amazonaws.com 2>&1 | grep '^< HTTP'

Plain HTTP on the same port returns the code normally.

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.

SOCKS5 has five reply bytes, so several causes share one.

ReplyCause
0x00Success
0x01Credentials not recognized, or over the request-rate limit
0x04Something failed on our side
0x05Blocked domain, or no exit matched your targeting
0x07 0x08Unsupported 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.

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?