{"record":{"id":"7f72a61d80877382","repo":"zeroclaw-labs/zeroclaw","slug":"gemini-token-refresh-is-in-backoff-for-remaining","errorCode":null,"errorMessage":"Gemini token refresh is in backoff for {remaining}s due to previous failures","messagePattern":"Gemini token refresh is in backoff for (.+?)s due to previous failures","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/zeroclaw-providers/src/auth/mod.rs","lineNumber":334,"sourceCode":"\n        // Re-load after waiting for lock to avoid duplicate refreshes.\n        let data = self.store.load().await?;\n        let Some(latest_profile) = data.profiles.get(&profile_id) else {\n            return Ok(None);\n        };\n\n        let Some(latest_tokens) = latest_profile.token_set.as_ref() else {\n            anyhow::bail!(\"Gemini auth profile is missing token set: {profile_id}\");\n        };\n\n        if !latest_tokens.is_expiring_within(Duration::from_secs(OPENAI_REFRESH_SKEW_SECS)) {\n            return Ok(Some(latest_tokens.access_token.clone()));\n        }\n\n        let refresh_token = latest_tokens.refresh_token.clone().unwrap_or(refresh_token);\n\n        if let Some(remaining) = refresh_backoff_remaining(&profile_id) {\n            anyhow::bail!(\n                \"Gemini token refresh is in backoff for {remaining}s due to previous failures\"\n            );\n        }\n\n        let mut refreshed = match refresh_gemini_access_token_with_retries(\n            &self.client,\n            client_id,\n            client_secret,\n            &refresh_token,\n        )\n        .await\n        {\n            Ok(tokens) => {\n                clear_refresh_backoff(&profile_id);\n                tokens\n            }\n            Err(err) => {\n                set_refresh_backoff(","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/auth/mod.rs#L316-L352","documentation":"Gemini variant of the refresh backoff guard: get_valid_gemini_access_token found the cached token expiring within 90 s, has a refresh token, but a previous Gemini refresh failed less than 10 s ago (OPENAI_REFRESH_FAILURE_BACKOFF_SECS). The remaining backoff seconds are embedded. The map is process-local and clears on a successful refresh.","triggerScenarios":"A refresh_gemini_access_token_with_retries call failed (wrong oauth_client_secret, network error, revoked refresh token) and any send_generate_content, warmup, or refresh_status call within the next 10 seconds takes this branch and bails with the remaining seconds.","commonSituations":"Rotated oauth_client_secret in Google Cloud not mirrored to [providers.models.gemini.<profile>], so every refresh fails and callers pile onto the backoff; transient network loss during startup; revoked Google refresh token after password/security events.","solutions":["Wait the embedded remaining seconds, then retry","Run auth refresh --model-provider gemini to surface the real refresh error; fix oauth_client_id/oauth_client_secret in the alias config if it is invalid_client","If the refresh token was revoked, re-run auth login --model-provider gemini"],"exampleFix":null,"handlingStrategy":"retry","validationCode":"// Backoff is at most 10s and process-local; pace retries wider than that.\ntokio::time::sleep(std::time::Duration::from_secs(10)).await;\nlet token = auth.get_valid_gemini_access_token(None, client_id, client_secret).await?;","typeGuard":null,"tryCatchPattern":"match auth.get_valid_gemini_access_token(override_, cid, secret).await {\n    Ok(tok) => tok,\n    Err(e) => {\n        let msg = e.to_string();\n        if msg.contains(\"refresh is in backoff\") {\n            let secs: u64 = msg.split(\"backoff for \").nth(1)\n                .and_then(|r| r.split('s').next()).and_then(|s| s.parse().ok()).unwrap_or(1);\n            tokio::time::sleep(std::time::Duration::from_secs(secs + 1)).await;\n            return auth.get_valid_gemini_access_token(override_, cid, secret).await;\n        }\n        Err(e)\n    }\n}","preventionTips":["Verify oauth_client_secret matches Google Cloud before refresh-heavy runs","Back off your own retries beyond 10 s so the guard never triggers","Fix revoked refresh tokens with a fresh auth login instead of grinding the guard"],"tags":["auth","oauth","gemini","backoff","rate-limit","rust"],"backgroundTag":"token-refresh-backoff","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}