zeroclaw-labs/zeroclaw · error · anyhow::Error
OpenAI OAuth error: {err} ({desc})
Error message
OpenAI OAuth error: {err} ({desc}) What it means
After splitting the pasted redirect input into query parameters, parse_code_from_redirect checks for an OAuth standard `error` parameter before looking for `code`. Its presence means the authorization server ended the flow with an error (e.g. access_denied, server_error, login_required) instead of issuing a code; the message embeds both the error code and its error_description (defaulting to 'OAuth authorization failed').
Source
Thrown at crates/zeroclaw-providers/src/auth/openai_oauth.rs:316
let query = if let Some((_, right)) = trimmed.split_once('?') {
right
} else {
trimmed
};
let params = parse_query_params(query);
let is_callback_payload = trimmed.contains('?')
|| params.contains_key("code")
|| params.contains_key("state")
|| params.contains_key("error");
if let Some(err) = params.get("error") {
let desc = params
.get("error_description")
.cloned()
.unwrap_or_else(|| "OAuth authorization failed".to_string());
anyhow::bail!("OpenAI OAuth error: {err} ({desc})");
}
if let Some(expected_state) = expected_state {
if let Some(got) = params.get("state") {
if got != expected_state {
anyhow::bail!("OAuth state mismatch");
}
} else if is_callback_payload {
anyhow::bail!("Missing OAuth state in callback");
}
}
if let Some(code) = params.get("code").cloned() {
return Ok(code);
}
if !is_callback_payload {
return Ok(trimmed.to_string());View on GitHub (pinned to 88bb9c8533)
Solutions
- Read ({err} ({desc})): access_denied means approval was refused — restart `auth login` and approve consent
- For login_required/session errors, sign in cleanly in the browser first, then redo the login flow
- Make sure to paste the final URL after successful consent (it should contain code=..., not error=...)
Defensive patterns
Strategy: try-catch
Validate before calling
// Cheap pre-check on the pasted URL before parsing
let query = pasted.split_once('?').map(|(_, q)| q).unwrap_or(pasted);
if query.split('&').any(|kv| kv.starts_with("error=")) {
anyhow::bail!("redirect contains an OAuth error param — consent did not succeed; restart auth login");
} Type guard
fn redirect_has_oauth_error(input: &str) -> bool {
input
.split_once('?')
.map(|(_, q)| q)
.unwrap_or(input)
.split('&')
.any(|kv| kv.starts_with("error=") || kv.starts_with("error_description="))
} Try / catch
match openai_oauth::parse_code_from_redirect(&pasted, Some(state)) {
Err(e) if e.to_string().starts_with("OpenAI OAuth error:") => {
// consent failed upstream; guide user to restart rather than retry the same paste
anyhow::bail!("authorization was not granted ({e}); re-run `zeroclaw auth login --model-provider openai-codex`");
}
other => other?,
} Prevention
- Paste only the post-consent URL — it must contain code=, not error=
- Handle access_denied/login_required descriptions as user-flow problems, not code bugs
- Restart the login flow instead of re-pasting an error redirect
When it happens
Trigger: Pasting a redirect URL like https://.../?error=access_denied&error_description=User+cancelled — the user denied consent, the session timed out at the IdP, or the authorization server failed — during `auth paste-redirect` for OpenAI.
Common situations: Canceling the consent dialog and pasting the resulting URL anyway, SSO session expiry mid-consent, or policy-blocked apps producing error redirects.
Related errors
- OpenAI device-code authorization was denied
- User denied authorization
- Pending login profile mismatch: pending={}, requested={}
- OpenAI device-code start failed ({status}): {body}
- Device-code flow timed out before authorization completed
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/98fdd320b5625df9.
Report an issue: GitHub.