zeroclaw-labs/zeroclaw · error · anyhow::Error
Gemini API error ({status}): {error_text}
Error message
Gemini API error ({status}): {error_text} What it means
The Gemini generateContent call returned non-2xx and none of the built-in recoveries applied: OAuth credential rotation was not possible or the rotated retry still failed, and the retry-without-generationConfig path did not match this error. The message carries the HTTP status and the raw upstream error text.
Source
Thrown at crates/zeroclaw-providers/src/gemini.rs:1301
}
_ => unreachable!(),
};
oauth_token = Some(new_token);
project = Some(new_project);
response = self
.build_generate_content_request(
auth,
&url,
&request,
model,
true,
project.as_deref(),
oauth_token.as_deref(),
)?
.send()
.await?;
} else {
anyhow::bail!("Gemini API error ({status}): {error_text}");
}
} else if auth.is_oauth()
&& Self::should_retry_oauth_without_generation_config(status, &error_text)
{
::zeroclaw_log::record!(
WARN,
::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)
.with_outcome(::zeroclaw_log::EventOutcome::Unknown),
"Gemini OAuth internal endpoint rejected generationConfig; retrying without generationConfig"
);
response = self
.build_generate_content_request(
auth,
&url,
&request,
model,
false,
project.as_deref(),View on GitHub (pinned to 88bb9c8533)
Solutions
- Read the status and body: 400 fix model/request fields, 401/403 fix the key or re-auth, 429/503 back off and retry
- Confirm the model id exists for your access level and the Generative Language API is enabled in the project
- For quota errors, switch model or raise limits, and add exponential backoff around the call
- Check the Google Cloud status dashboard for Gemini incidents
Defensive patterns
Strategy: retry
Validate before calling
// Validate the model id shape before spending quota
fn is_valid_gemini_model(model: &str) -> bool {
let m = model.strip_prefix("models/").unwrap_or(model);
!m.is_empty() && m.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '.' | '_'))
}
if !is_valid_gemini_model(model) {
anyhow::bail!("invalid Gemini model id: {model}");
} Try / catch
let mut attempt = 0;
loop {
match provider.chat_with_system(None, prompt, model, None).await {
Ok(text) => break Ok(text),
Err(e) => {
let msg = e.to_string();
let retryable = msg.contains("HTTP 429") || msg.contains("HTTP 503");
if retryable && attempt < 4 {
attempt += 1;
tokio::time::sleep(std::time::Duration::from_millis(
500u64 * (1 << attempt),
)).await;
continue;
}
break Err(e); // 400/401/403: fix model id, key, or access level
}
}
} Prevention
- Keep an allowlist of model ids per environment so typos fail at config time
- Retry 429/503 with exponential backoff; treat 400/401/403 as terminal
- Monitor quota dashboards for projects serving production traffic
- Check Google Cloud status before debugging persistent 5xx from Gemini
When it happens
Trigger: 400 invalid model name or malformed payload; 401/403 invalid API key or OAuth token without access; 429 quota exhausted; 503 model overloaded - reached after automatic OAuth retries were exhausted or skipped (API-key auth has no retry path).
Common situations: Typo'd model id (must be a valid models/... name); free-tier quota exhausted; API key from a GCP project without the Generative Language API enabled; Gemini incidents.
Related errors
- Google device code request failed ({}): {}
- {} API error ({status}): {sanitized}
- Gemini CLI OAuth refresh failed (HTTP {status}): {body}
- Gemini CLI OAuth token expired and no refresh_token availabl
- WhatsApp API error: {status}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/05df646e05ba9a0a.
Report an issue: GitHub.