zeroclaw-labs/zeroclaw · warning
OpenAI token refresh is in backoff for {remaining}s due to p
Error message
OpenAI token refresh is in backoff for {remaining}s due to previous failures What it means
get_valid_openai_access_token attempted a refresh path and hit the in-process backoff guard: a previous refresh attempt already failed within the last OPENAI_REFRESH_FAILURE_BACKOFF_SECS (10 s), so refresh_backoff_remaining returned a remaining window and the call bails fast instead of hammering the token endpoint. The backoff lives in a process-wide static map keyed by profile_id and clears on success or expiry.
Source
Thrown at crates/zeroclaw-providers/src/auth/mod.rs:246
// 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!("OpenAI Codex 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!(
"OpenAI token refresh is in backoff for {remaining}s due to previous failures"
);
}
let mut refreshed =
match refresh_openai_access_token_with_retries(&self.client, &refresh_token).await {
Ok(tokens) => {
clear_refresh_backoff(&profile_id);
tokens
}
Err(err) => {
set_refresh_backoff(
&profile_id,
Duration::from_secs(OPENAI_REFRESH_FAILURE_BACKOFF_SECS),
);
return Err(err);
}
};View on GitHub (pinned to 88bb9c8533)
Solutions
- Wait the embedded number of seconds (plus margin) and retry the call — the backoff expires automatically
- Find the underlying refresh failure: run auth refresh --model-provider openai-codex and read the real error (often an expired/revoked refresh token)
- If the refresh token is revoked, re-authenticate with auth login --model-provider openai-codex
- Restarting the process also clears the in-memory backoff, but only do that after fixing the root cause
Defensive patterns
Strategy: retry
Validate before calling
// The backoff window is at most 10s and lives in-process; schedule resolution // at least that long after any known refresh failure. // (No public accessor exists — pace your own retries instead.) tokio::time::sleep(std::time::Duration::from_secs(10)).await; let token = auth.get_valid_openai_access_token(None).await?;
Try / catch
match auth.get_valid_openai_access_token(None).await {
Ok(tok) => tok,
Err(e) => {
let msg = e.to_string();
if let Some(rest) = msg.split("backoff for ").nth(1) {
let secs: u64 = rest.split('s').next().unwrap_or("0").parse().unwrap_or(1);
tokio::time::sleep(std::time::Duration::from_secs(secs + 1)).await;
return auth.get_valid_openai_access_token(None).await;
}
Err(e)
}
} Prevention
- Space credential-resolution attempts more than 10 s apart after a failure
- Diagnose the underlying refresh error instead of retrying through the guard forever
- Remember the backoff map is per-process: a restart clears it, fixing nothing
When it happens
Trigger: The cached access token is within 90 s of expiry (OPENAI_REFRESH_SKEW_SECS) or past it, a refresh_token exists, and an earlier refresh_openai_access_token_with_retries call failed — every get_valid_openai_access_token call within the following 10 seconds bails with the remaining seconds embedded.
Common situations: A short outage at the OpenAI token endpoint while a scheduler retries authentication repeatedly; the refresh token was revoked server-side so each refresh fails and callers stack up on the backoff; multiple tasks resolving credentials at boot after the network dropped.
Related errors
- Gemini token refresh is in backoff for {remaining}s due to p
- xAI token refresh is in backoff for {remaining}s due to prev
- OpenAI Codex auth profile is not OAuth-based: {profile_id}
- OpenAI Codex auth profile is missing token set: {profile_id}
- Gemini auth profile is not OAuth-based: {profile_id}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/48559e7c61d75ce8.
Report an issue: GitHub.