Gemini API 429 error: RESOURCE_EXHAUSTED (and how to fix it)
The Gemini API returns a 429 status with the error code RESOURCE_EXHAUSTED when you've exceeded one of its rate limits. Unlike a flat "too many requests," Gemini's error body tells you exactly which quota you hit — read it before you write a retry loop.
The 30-second answer
- Read the error body — the
quotaMetricfield names the specific limit (requests/minute, tokens/minute, or requests/day) you exceeded. - Fix: exponential backoff with jitter for transient spikes; reduce concurrency; batch/cache repeated context to cut token volume.
- If you're on the free tier, the fastest fix is enabling billing — free-tier limits are deliberately tight and paid limits are much higher.
Step 1 — read the error body
Gemini's 429 response includes a structured error with the specific quota that was exceeded:
{
"error": {
"code": 429,
"message": "Resource has been exhausted (e.g. check quota).",
"status": "RESOURCE_EXHAUSTED"
}
}
Check the response headers and your Google Cloud project's quota dashboard to see which specific metric (RPM, TPM, or RPD) triggered it — the fix is different depending on which one you hit.
Case A: you're bursting too fast (RPM/TPM)
You've exceeded requests-per-minute or tokens-per-minute for your tier and model.
Fix it:
- Exponential backoff with jitter. Sleep, retry, grow the delay each attempt (1s, 2s, 4s…) with a little randomness so concurrent clients don't retry in lockstep.
- Reduce concurrency. Queue and pace requests client-side instead of bursting.
- Use context caching for repeated large prompts — it cuts the token volume that counts against your TPM limit. See how prompt caching works for the general pattern (Gemini's context caching works similarly).
- Route high-volume, low-complexity calls to Flash or Flash-Lite instead of Pro — smaller models often carry higher throughput limits.
import time, random
def call_with_backoff(fn, max_attempts=5, **kwargs):
for attempt in range(max_attempts):
try:
return fn(**kwargs)
except ResourceExhausted:
if attempt < max_attempts - 1:
time.sleep((2 ** attempt) + random.uniform(0, 1))
continue
raise
Case B: you've hit your daily cap (RPD)
Requests-per-day limits reset on a rolling or daily window depending on your tier. Retrying immediately won't help — you need to either wait for the reset or raise your quota.
Fix it: if this happens regularly, it's a signal your usage has outgrown your current tier. Enable billing on the Google Cloud project tied to your API key, or request a quota increase through the console if you're already billed.
Free tier vs paid tier limits
Gemini's free tier is intended for testing and evaluation, not production volume — its per-minute and per-day caps are deliberately tight. Enabling billing raises RPM, TPM, and RPD limits substantially, often by an order of magnitude. If you're building anything beyond a prototype, budget for the paid tier from the start rather than discovering the free-tier ceiling in production. Full pricing breakdown: Gemini API pricing.
How to stop hitting 429s in the first place
- Keep a client-side limiter under your known RPM/TPM ceilings rather than discovering them via errors.
- Use the Batch API for large, non-urgent jobs so they don't compete with live traffic.
- Cache repeated context instead of resending it every call.
- Monitor your Google Cloud quota dashboard so a rising day-over-day trend doesn't surprise you.
FAQ
Is this the same as OpenAI's or Anthropic's 429? Same HTTP status code, different underlying cause and error format. See our guides on OpenAI's 429 and Claude's 529 overloaded error for the equivalents on those platforms.
How many retries? A handful (4–5) with exponential backoff for RPM/TPM limits. For a daily cap, retrying won't help — wait for reset or raise your quota.
Related
Regularly reviewed and kept current. Behavior verified against Google's published Gemini API error and quota documentation. Confirm current limits in the official docs before relying on specifics in production.