zeroclaw-labs/zeroclaw · error
Gemini auth profile is not OAuth-based: {profile_id}
Error message
Gemini auth profile is not OAuth-based: {profile_id} What it means
The Gemini counterpart of error 670: get_valid_gemini_access_token selected a gemini profile whose token_set is None, meaning the stored credential is a bearer token rather than an OAuth token set. The function needs a token_set to check expiry and refresh; a token-kind profile violates that contract and bails.
Source
Thrown at crates/zeroclaw-providers/src/auth/mod.rs:303
}
pub async fn get_valid_gemini_access_token(
&self,
profile_override: Option<&str>,
client_id: &str,
client_secret: &str,
) -> Result<Option<String>> {
let data = self.store.load().await?;
let Some(profile_id) = select_profile_id(&data, GEMINI_PROVIDER, profile_override) else {
return Ok(None);
};
let Some(profile) = data.profiles.get(&profile_id) else {
return Ok(None);
};
let Some(token_set) = profile.token_set.as_ref() else {
anyhow::bail!("Gemini auth profile is not OAuth-based: {profile_id}");
};
if !token_set.is_expiring_within(Duration::from_secs(OPENAI_REFRESH_SKEW_SECS)) {
return Ok(Some(token_set.access_token.clone()));
}
let Some(refresh_token) = token_set.refresh_token.clone() else {
return Ok(Some(token_set.access_token.clone()));
};
let refresh_lock = refresh_lock_for_profile(&profile_id);
let _guard = refresh_lock.lock().await;
// 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);
};View on GitHub (pinned to 88bb9c8533)
Solutions
- Run auth login --model-provider gemini --profile <name> to complete the Google OAuth flow and store a token_set
- Verify you are selecting the right profile: list profiles and their kinds before passing profile_override
- If a bearer/API-key profile is intended, route through get_provider_bearer_token instead
Defensive patterns
Strategy: validation
Validate before calling
let data = auth.load_profiles().await?;
if let Some(profile) = data.profiles.get(&format!("gemini:{}", name)) {
anyhow::ensure!(profile.token_set.is_some(), "gemini profile {name} is a bearer token, not OAuth");
}
let token = auth.get_valid_gemini_access_token(Some(name), client_id, client_secret).await?; Type guard
fn is_oauth_profile(p: &AuthProfile) -> bool {
p.token_set.is_some()
} Try / catch
match auth.get_valid_gemini_access_token(override_, cid, secret).await {
Ok(tok) => tok,
Err(e) if e.to_string().contains("not OAuth-based") => {
eprintln!("run auth login --model-provider gemini to create an OAuth profile");
return Err(e);
}
Err(e) => return Err(e),
} Prevention
- Use auth login --model-provider gemini for profiles that feed OAuth resolvers
- Check token_set presence before calling send_generate_content paths
- Keep bearer-token profiles on get_provider_bearer_token
When it happens
Trigger: Calling send_generate_content, warmup, or refresh_status for gemini when the active profile was created via auth paste-token; selecting such a profile through profile_override; a hand-edited or migrated profiles file with a null token_set.
Common situations: User pasted an API key for Gemini but the runtime path calls the OAuth resolver; the alias profile in [providers.models.gemini.<profile>] was set up with a token instead of the OAuth login flow.
Related errors
- Gemini auth profile is missing token set: {profile_id}
- OpenAI Codex auth profile is not OAuth-based: {profile_id}
- OpenAI Codex auth profile is missing token set: {profile_id}
- Gemini token refresh is in backoff for {remaining}s due to p
- xAI auth profile is not OAuth-based: {profile_id}
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/dc9547789282c18f.
Report an issue: GitHub.