When the Gemini API answers with 503 The model is overloaded. Please try again later., nothing is wrong with your request. Google's capacity for that model is temporarily saturated.
google.api_core.exceptions.ServiceUnavailable: 503 The model is overloaded.
Please try again later.
The Gemini CLI shows the same condition inline:
[API Error: The model is overloaded. Please try again later.]
Google documents the 503 status as service_unavailable — "The service is temporarily overloaded or down" — with the recommended solution being to "Wait and retry with exponential backoff."
Why This Happens
Gemini models run on shared infrastructure. Demand for a given model fluctuates, and when scheduling pressure exceeds available capacity, the service sheds load by returning 503 rather than queueing your request indefinitely.
Three things follow from that, and they save a lot of wasted debugging:
- It is not a quota problem. A 429 RESOURCE_EXHAUSTED means you exceeded your allowance. A 503 means the service is busy regardless of your usage. Raising your quota tier will not prevent it.
- It is not an authentication problem. An invalid or unauthorised key returns 400 or 403. A 503 means your credentials were accepted.
- It is per model. Capacity is tracked per model and per version, so a newly launched or unusually popular model returns 503 far more often than an established one.
Fix 1: Retry With Exponential Backoff
This is the documented remedy and it resolves the overwhelming majority of cases without any other change. Google's troubleshooting guidance names 503 explicitly as an error you should retry, alongside 429 and other 5xx responses, while advising against retrying client errors such as 400 and 403.
import random, time
from google.api_core import exceptions
def call_with_backoff(fn, max_attempts=5, cap=60):
for attempt in range(max_attempts):
try:
return fn()
except (exceptions.ServiceUnavailable, exceptions.ResourceExhausted):
if attempt == max_attempts - 1:
raise
delay = min(cap, (2 ** attempt)) + random.uniform(0, 1)
time.sleep(delay)
Two details matter more than they look:
- Jitter. Without a random component, every client that hit the overload retries in lockstep and recreates the spike that caused it.
- A cap on attempts. Unbounded retries turn a transient service condition into a stuck queue, and add load to a service that is already saturated.
Fix 2: Fall Back to Another Model
Because capacity is per model, a fallback chain often succeeds immediately during an overload:
MODELS = ["gemini-2.5-pro", "gemini-2.5-flash"]
def generate(prompt):
last_error = None
for model in MODELS:
try:
return call_model(model, prompt)
except exceptions.ServiceUnavailable as e:
last_error = e
raise last_error
Order the chain by capability, and be deliberate about it — a Flash model answering when Pro is unavailable is usually better than no answer, but not for every workload. Our guide on switching models covers the trade-offs.
Fix 3: Shift Non-Urgent Work Off Peak
Batch jobs do not need to run during peak demand. Moving bulk summarisation, enrichment, or evaluation runs to quieter hours both reduces the 503 rate and leaves daytime capacity for interactive traffic. Where the platform offers it, an asynchronous batch API is designed for exactly this and is far more tolerant of scheduling pressure than synchronous calls.
Fix 4: Reserve Capacity for Production
If a 503 during business hours is genuinely unacceptable, the architectural answer is reserved capacity rather than more aggressive retries. Vertex AI offers provisioned throughput, which reserves capacity for your project instead of competing for the shared pool. It costs more and is worth evaluating only when retry and fallback are demonstrably insufficient.
Make Sure It Really Is a 503
Three server-side codes get conflated, and they call for different responses. Google documents them distinctly:
| Code | Reason | Documented cause | Documented fix |
|---|---|---|---|
| 500 | api_error | "An unexpected error occurred on the server." | "Retry the request. If it persists, contact support." |
| 503 | service_unavailable | "The service is temporarily overloaded or down." | "Wait and retry with exponential backoff." |
| 504 | deadline_exceeded | "The request didn't finish within the deadline." | "Remove or increase client deadline setting to use the server default." |
If very large prompts fail consistently while small ones succeed, you are probably looking at a 504, not a 503 — and the fix is your client timeout, not patience. A persistent 500 on a request that is otherwise valid is worth reporting rather than retrying indefinitely. Log the numeric status alongside the message so this distinction survives into your metrics.
Verify the Fix
Send one small request and read the status code directly:
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'
A 200 confirms capacity has recovered. If a one-token request still returns 503 while a different model returns 200, the overload is specific to that model and your fallback chain is the right lever.
Prevent It From Recurring
- Treat 503 as normal. Any production Gemini integration needs retry with jitter and a model fallback path built in from day one.
- Distinguish error classes in your monitoring. Alerting that lumps 429, 503, and 400 together hides the only signal that tells you whether the fix is yours or Google's.
- Cap retries and degrade gracefully. Queue the work, cache a previous answer, or tell the user plainly — never spin.
- Log the model name with every failure. Per-model 503 rates are what justify a fallback order, and you cannot see them without that field.
- Do not raise your quota tier in response to a 503. It addresses a limit you did not hit.