API rate limit exceeded: how to fix RATE_LIMIT_EXCEEDED
{
"error": {
"type": "rate_limited",
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests: limit is 5 per 60s"
}
}
Too many requests in the window. This is about call frequency, not about how many jobs are running — that is a different 429.
The limits
| Tier | Requests per minute |
|---|---|
| Free | 5 |
| Pro | 60 |
Tier is resolved from your subscription state at request time. If the lookup fails for any reason the gateway falls back to the free-tier limit, on the principle that a temporary database problem should degrade you rather than 5xx you.
It is a sliding window, and it counts the current request
Two implementation details that change how you should back off:
Sliding, not fixed. There is no “top of the minute” that resets the counter. Waiting for a round clock boundary does not help; waiting out the window does.
The current request is counted before the comparison. This closes a real
gap — under concurrency, two requests arriving together would otherwise each
see count = limit - 1 and both be let through.
Backing off
Exponential backoff with jitter, as usual. The specific thing worth noting for agent code: a 429 here is not a signal that anything is wrong with your request. Retrying the identical payload after a wait is correct, and the agent does not need to reason about it or report it as a failure.
A fixed-delay retry across several parallel workers is the pattern that reliably makes this worse — they resynchronise and hit the window together again. Jitter is what breaks that up.
If you are hitting 5/minute constantly
That is the free tier working as designed rather than a problem to tune
around. Pro raises it to 60. If you are batching images, note that n up to 4
puts four images in one request — which counts once against this limit.
Where these facts come from
- codebase: src/ai/api/rate-limit.ts — sliding window implementation
- codebase: src/ai/api/quota.ts — FREE_QUOTA and PRO_QUOTA