429 Too Many Requests: how to fix it on both sides

A 429 means the server understood the request, found nothing wrong with it, and refused it because it arrived too often. That is different from a rejection and different from a block: the request was valid, and the same request will succeed later. What to do about it depends entirely on which end of it you are.

Section Rate limiting Updated Two sides receiving / sending

If you are receiving 429

Five steps, in this order, because the first two solve most cases.

Stop retrying immediately. The commonest cause of a 429 that will not go away is the client's own retry loop: the refusal arrives, the client retries at once, that retry is also refused, and the pattern that triggered the limit is now sustained by the attempt to escape it. Check this before anything else, because a client written to retry on failure treats rate refusal as an ordinary error and does the wrong thing with it.

Look for Retry-After. If the response carries it, that is the server telling you when to come back, and honouring it is both the fastest route to success and the cheapest thing you can do. Where it is absent, back off progressively rather than at a fixed interval, and add a little randomness so that many clients refused together do not all return at the same moment. What that header does and why it is worth sending is covered under Retry-After.

Count what you are actually sending. A surprising share of limits are hit by clients doing work they do not need: polling for something that could be delivered once, fetching in a loop what could be fetched in one request, or re-requesting the same unchanged resource. Fixing that removes the limit as a problem rather than working around it.

Consider that it may not be about you. If you share an outbound address with other people, an office, a shared platform, a mobile network, you can be refused because of traffic that was never yours. That failure mode, and why counting by address produces it, is set out under per-IP versus per-user.

Ask, if it is somebody else's service. Where the limit belongs to a provider you use, the productive move is a conversation about your usage pattern, not persistence. No amount of retrying changes a limit, and sustained retrying is the behaviour most likely to get a client treated as hostile.

RETRY IMMEDIATELY 429429 429429 429429 429429 // the pattern that triggered the limit is now sustained // by the attempt to escape it HONOUR RETRY-AFTER 429 WAIT AS THE SERVER SAID, WITH A LITTLE RANDOMNESS SUCCEEDS
// the same request will succeed later — that is what separates it from a rejection

If you are sending 429

Five causes, in the order you should check them.

The limit is doing its job. The client really is asking too often, and the refusal is correct. This is the case the limit exists for, and the check that confirms it is concentration: one client, or a small number, receiving most of the refusals.

The limit is too low for a normal burst. Ordinary clients are not smooth. A page that loads several resources at once, an application that syncs on opening, a batch that runs after a deployment: each produces a short spike inside an otherwise modest average. A limit set on the average refuses them all, which is the subject of bursts.

The subject of the limit is wrong. Counting by address when your users share addresses refuses whole offices for the behaviour of one person, and counting by account when the abuse arrives from thousands of accounts counts nothing useful. Choosing the subject is a separate decision from choosing the number.

The client cannot tell when to return. A refusal without Retry-After leaves a well-behaved client guessing, and the common guess is to try again straight away. This turns one refused request into a stream of them and makes your own limit look like it is not working.

Something of yours is being limited. Your monitoring, your own integration, a job that fetches your site on a schedule: all of these arrive looking like anybody else. Check this before assuming an outside cause: the traffic is familiar to you and completely anonymous to the limit.

What a good 429 contains

Three things, and the third is the one usually missing.

The status itself, so a client can distinguish rate refusal from any other failure and respond correctly. A Retry-After value, so it knows when to come back instead of guessing. And a short readable explanation in the body, since some of the clients that receive it are people looking at a browser rather than software parsing a response.

Two things to avoid. Do not use 429 for authorisation problems, which are a different answer to a different question, and do not use a generic error for rate refusal, because a client cannot tell the difference and its retry behaviour will be wrong in the way that costs you most.

the shape of a refusal a client can act on
HTTP/1.1 429 Too Many Requests
Retry-After: 30
Content-Type: text/plain

Too many requests for this domain. Try again in 30 seconds.

Checking that yours behaves

Read the refusals by client rather than in total.

Concentration on one client is the intended outcome, and it is what a working limit looks like. A thin spread across many different clients usually means the limit or its subject is wrong rather than that everybody started misbehaving on the same afternoon, and the same reading applies after any change: compare the same route before and after instead of looking at the count on its own.

Bridge WAF applies rate limiting per domain, and the surrounding decisions, which subject to count and how to handle bursts, remain yours to make in your own stack. See how that fits the rest of the delivery path at Bridge CDN.

CONCENTRATED ON ONE CLIENT THE LIMIT WORKING AS INTENDED SPREAD THINLY ACROSS MANY THE LIMIT OR ITS SUBJECT IS WRONG THE SAME NUMBER OF REFUSALS IN BOTH // nobody starts misbehaving on the same afternoon // read them by client, never in total
// concentration is the signal, and the total is not

Questions

What does 429 actually mean?

That the request was understood and valid but arrived too often, so it was refused for rate rather than for content. The same request will succeed later, which is what separates it from a rejection you need to fix by changing what you send.

How long should I wait before retrying?

As long as Retry-After says, if the response carries it, since that is the server stating its own answer rather than you guessing at one. Without it, back off progressively and add a little randomness, so that clients refused at the same moment do not all return together and reproduce the condition that refused them.

Why am I being limited when I barely send requests?

Most often because the count is not about you alone. Shared outbound addresses mean an office, a campus, or a mobile network can be counted as a single client, so the traffic that crossed the limit may have been somebody else's entirely and there is nothing in your own usage that would explain it.

Should I use 429 or just block the client?

Use 429 when the client is welcome but too frequent, since it tells them the truth and lets a well-behaved one adjust. Blocking answers a different question, and using it for rate makes ordinary clients look hostile in your own record.

Where the platform sits

Rate limiting is applied per domain. Which subject to count and how to handle bursts remain yours to decide, in your own stack.

off

Nothing is counted, and nothing is refused for rate.

monitor

What a limit would have refused is recorded. Read it by client before enforcing.

block

Requests past the limit receive the refusal, and are still recorded.

The firewall layer is included with Bridge CDN. Start in monitor: nothing is refused until you decide it should be.

Get started