429, defined in RFC 6585, is the polite way for a server to say "slow down". It may include a Retry-After header, either a number of seconds or an HTTP date, telling you when it will accept requests again.
Who sent it
Through a proxy, a 429 can come from two places:
- The website. It arrives after the tunnel is established, and means the site's rate limit for your IP, account or session was exceeded.
- The proxy provider. Some providers return 429 when you exceed a plan limit such as concurrent connections. It arrives on the CONNECT response, before the site is involved.
curl -v shows which: a 429 in reply to the CONNECT line is the proxy's; one after Connection established is the site's.
Handle it in code
Honour Retry-After when it is present; otherwise back off exponentially with jitter:
import random
def backoff_seconds(response, attempt):
retry_after = response.headers.get("Retry-After", "")
if retry_after.isdigit():
return int(retry_after)
return min(60, 2 ** attempt) + random.random()
Sleep for the returned time, retry, and give up after a few attempts rather than looping forever.
Common confusion
The tempting fix is to rotate to fresh IPs every time a 429 arrives. That spreads a per-IP limit, but it does not help when the limit is on your account or session, and it treats a clear request to slow down as an obstacle. Our allowed-use policy asks you to respect rate limits. Lower your concurrency per host first. The proxy error codes guide covers 429 alongside the other codes you will meet.