zeroclaw-labs/zeroclaw · warning
Gemini token refresh is in backoff for {remaining}s due to p
Error message
Gemini token refresh is in backoff for {remaining}s due to previous failures What it means
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.
Source
Thrown at crates/zeroclaw-providers/src/auth/mod.rs:334
// Re-load after waiting for lock to avoid duplicate refreshes.
let data = self.store.load().await?;
let Some(latest_profile) = data.profiles.get(&profile_id) else {
return Ok(None);
};
let Some(latest_tokens) = latest_profile.token_set.as_ref() else {
anyhow::bail!("Gemini auth profile is missing token set: {profile_id}");
};
if !latest_tokens.is_expiring_within(Duration::from_secs(OPENAI_REFRESH_SKEW_SECS)) {
return Ok(Some(latest_tokens.access_token.clone()));
}
let refresh_token = latest_tokens.refresh_token.clone().unwrap_or(refresh_token);
if let Some(remaining) = refresh_backoff_remaining(&profile_id) {
anyhow::bail!(
"Gemini token refresh is in backoff for {remaining}s due to previous failures"
);
}
let mut refreshed = match refresh_gemini_access_token_with_retries(
&self.client,
client_id,
client_secret,
&refresh_token,
)
.await
{
Ok(tokens) => {
clear_refresh_backoff(&profile_id);
tokens
}
Err(err) => {
set_refresh_backoff(View on GitHub (pinned to 88bb9c8533)
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
Defensive patterns
Strategy: retry
Validate before calling
// Backoff is at most 10s and process-local; pace retries wider than that. tokio::time::sleep(std::time::Duration::from_secs(10)).await; let token = auth.get_valid_gemini_access_token(None, client_id, client_secret).await?;
Try / catch
match auth.get_valid_gemini_access_token(override_, cid, secret).await {
Ok(tok) => tok,
Err(e) => {
let msg = e.to_string();
if msg.contains("refresh is in backoff") {
let secs: u64 = msg.split("backoff for ").nth(1)
.and_then(|r| r.split('s').next()).and_then(|s| s.parse().ok()).unwrap_or(1);
tokio::time::sleep(std::time::Duration::from_secs(secs + 1)).await;
return auth.get_valid_gemini_access_token(override_, cid, secret).await;
}
Err(e)
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- OpenAI token refresh is in backoff for {remaining}s due to p
- xAI token refresh is in backoff for {remaining}s due to prev
- Gemini auth profile is not OAuth-based: {profile_id}
- Gemini auth profile is missing token set: {profile_id}
- Google device code request failed ({}): {}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/7f72a61d80877382.
Report an issue: GitHub.