{"record":{"id":"05df646e05ba9a0a","repo":"zeroclaw-labs/zeroclaw","slug":"gemini-api-error-status-error-text","errorCode":null,"errorMessage":"Gemini API error ({status}): {error_text}","messagePattern":"Gemini API error \\((.+?)\\): (.+?)","errorType":"http","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/gemini.rs","lineNumber":1301,"sourceCode":"                        }\n                        _ => unreachable!(),\n                    };\n                    oauth_token = Some(new_token);\n                    project = Some(new_project);\n                    response = self\n                        .build_generate_content_request(\n                            auth,\n                            &url,\n                            &request,\n                            model,\n                            true,\n                            project.as_deref(),\n                            oauth_token.as_deref(),\n                        )?\n                        .send()\n                        .await?;\n                } else {\n                    anyhow::bail!(\"Gemini API error ({status}): {error_text}\");\n                }\n            } else if auth.is_oauth()\n                && Self::should_retry_oauth_without_generation_config(status, &error_text)\n            {\n                ::zeroclaw_log::record!(\n                    WARN,\n                    ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Note)\n                        .with_outcome(::zeroclaw_log::EventOutcome::Unknown),\n                    \"Gemini OAuth internal endpoint rejected generationConfig; retrying without generationConfig\"\n                );\n                response = self\n                    .build_generate_content_request(\n                        auth,\n                        &url,\n                        &request,\n                        model,\n                        false,\n                        project.as_deref(),","sourceCodeStart":1283,"sourceCodeEnd":1319,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/gemini.rs#L1283-L1319","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Validate the model id shape before spending quota\nfn is_valid_gemini_model(model: &str) -> bool {\n    let m = model.strip_prefix(\"models/\").unwrap_or(model);\n    !m.is_empty() && m.chars().all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '.' | '_'))\n}\nif !is_valid_gemini_model(model) {\n    anyhow::bail!(\"invalid Gemini model id: {model}\");\n}","typeGuard":null,"tryCatchPattern":"let mut attempt = 0;\nloop {\n    match provider.chat_with_system(None, prompt, model, None).await {\n        Ok(text) => break Ok(text),\n        Err(e) => {\n            let msg = e.to_string();\n            let retryable = msg.contains(\"HTTP 429\") || msg.contains(\"HTTP 503\");\n            if retryable && attempt < 4 {\n                attempt += 1;\n                tokio::time::sleep(std::time::Duration::from_millis(\n                    500u64 * (1 << attempt),\n                )).await;\n                continue;\n            }\n            break Err(e); // 400/401/403: fix model id, key, or access level\n        }\n    }\n}","preventionTips":["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"],"tags":["gemini","api-error","http","google","rust"],"backgroundTag":"llm-api-error","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}