When the Gemini API returns 429 RESOURCE_EXHAUSTED, your key is valid and your request is well formed. You have simply asked for more than your allowance permits.
google.api_core.exceptions.ResourceExhausted: 429 Resource has been exhausted
(e.g. check quota).
The Gemini CLI surfaces the same condition in plainer language:
[API Error: You exceeded your current quota. Please try again later.]
Before changing anything, work out which limit you hit — because two very different failures share this one status code.
Why This Happens
Google documents two distinct reasons behind a 429:
| Reason | Documented cause | Documented fix |
|---|---|---|
rate_limit_exceeded | "You have exceeded the per-minute or per-second request or token limit." | "Wait and retry with exponential backoff." |
quota_exceeded | "You have exceeded your daily quota." | "Wait until the quota resets or request a quota increase." |
The practical difference is enormous. A rate limit clears in seconds; a daily quota does not clear until it resets, and no amount of retrying will get you through it.
Read the error body rather than the status line — the nested reason field names which one applied. A quick behavioural test works too: if a retry 30 seconds later succeeds, it was a rate limit. If it fails identically for hours, it was your daily quota.
Note that Gemini meters requests per minute and tokens per minute separately. A handful of long-context prompts can exhaust the token allowance while your request count still looks trivially low. This is the single most common source of a "but I only made four calls" 429.
Fix 1: Add Exponential Backoff (Rate Limits)
Google's troubleshooting guidance is explicit: if you receive an error indicating you should retry — such as 429 RESOURCE_EXHAUSTED or 503 UNAVAILABLE — implement an exponential backoff strategy. Retry only transient errors such as 429, 408, and 5xx, never client errors such as 400 or 403, which indicate an invalid key or bad syntax and will fail identically forever.
import random, time
from google.api_core import exceptions
def call_with_backoff(fn, max_attempts=5):
for attempt in range(max_attempts):
try:
return fn()
except exceptions.ResourceExhausted:
if attempt == max_attempts - 1:
raise
delay = (2 ** attempt) + random.uniform(0, 1) # jitter
time.sleep(delay)
The jitter matters. Without it, every worker that hit the limit retries at the same instant and re-triggers it together.
Fix 2: Reduce Concurrency
Parallel workers multiply your request rate by the worker count, which is how batch jobs hit a per-minute ceiling that interactive use never touches. Cap concurrency deliberately rather than letting your thread or task pool decide, and add a small delay between calls in tight loops.
Fix 3: Cut Token Consumption
Because tokens are metered independently, trimming input often resolves a 429 that request-count tuning cannot:
- Send only the context the model needs, not the entire file or conversation history.
- Cap output with
max_output_tokensso runaway generations do not consume the allowance. - Batch several small questions into one request instead of issuing many.
- Use context caching for a large corpus you query repeatedly.
Fix 4: Move Work to a Lighter Model
Limits are set per model. A Flash model generally carries a higher allowance than a Pro model, so routing classification, extraction, and summarisation to Flash leaves Pro headroom for the reasoning work that actually needs it.
Fix 5: Raise the Quota (Daily Limits)
If the reason is quota_exceeded, the fix is administrative rather than technical. Check your tier's published rate limits in Google AI Studio, and for a Google Cloud project open IAM & Admin > Quotas in the Cloud console to view current usage and file an increase request. Moving from the free tier to a paid tier raises limits substantially — if you are hitting a daily cap in normal use, that is usually the honest answer.
Verify the Fix
Confirm with a single small request rather than by re-running the job that failed:
curl -s "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.5-flash:generateContent" \
-H "x-goog-api-key: $GEMINI_API_KEY" \
-H 'Content-Type: application/json' \
-d '{"contents":[{"parts":[{"text":"ping"}]}]}' \
-o /dev/null -w '%{http_code}\n'
200 means you have headroom again. A repeated 429 on a one-token request is a strong sign you are against a daily quota rather than a per-minute rate limit.
Prevent It From Recurring
- Build backoff in from the start. Every production Gemini client needs retry with jitter — this error is a normal operating condition, not an exception.
- Instrument token usage, not just call counts. The token limit is the one most teams hit first, and the one least often monitored.
- Separate keys or projects per environment so a runaway development script cannot consume the allowance production depends on.
- Fail gracefully. Queue the work or degrade the feature rather than surfacing a raw 429 to your users.
- Watch for the 503 case too — an overloaded model is a different failure with a similar remedy, covered in our Gemini 503 model overloaded guide.
If you are still setting up access, our guides on getting a Gemini API key and switching models cover the configuration side.