Genace

API rate limit exceeded: how to fix RATE_LIMIT_EXCEEDED

HTTP 429 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

TierRequests per minute
Free5
Pro60

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