{"record":{"id":"a3577c35416d7d85","repo":"zeroclaw-labs/zeroclaw","slug":"openai-device-code-polling-failed-status","errorCode":null,"errorMessage":"OpenAI device-code polling failed ({status}): {}","messagePattern":"OpenAI device-code polling failed \\((.+?)\\): (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/auth/openai_oauth.rs","lineNumber":216,"sourceCode":"        let text = response.text().await.unwrap_or_default();\n\n        if let Ok(err) = serde_json::from_str::<OAuthErrorResponse>(&text) {\n            match err.error.as_str() {\n                \"authorization_pending\" => {\n                    continue;\n                }\n                \"slow_down\" => {\n                    interval_secs = interval_secs.saturating_add(5);\n                    continue;\n                }\n                \"access_denied\" => {\n                    anyhow::bail!(\"OpenAI device-code authorization was denied\")\n                }\n                \"expired_token\" => {\n                    anyhow::bail!(\"OpenAI device-code expired\")\n                }\n                _ => {\n                    anyhow::bail!(\n                        \"OpenAI device-code polling failed ({status}): {}\",\n                        err.error_description.unwrap_or(err.error)\n                    )\n                }\n            }\n        }\n\n        anyhow::bail!(\"OpenAI device-code polling failed ({status}): {text}\");\n    }\n}\n\npub async fn receive_loopback_code(expected_state: &str, timeout: Duration) -> Result<String> {\n    ::zeroclaw_log::scope!(\n        model_provider_type: \"openai\",\n        model_provider_alias: \"oauth\",\n        => async move {\n            receive_loopback_code_inner(expected_state, timeout).await\n        }","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/auth/openai_oauth.rs#L198-L234","documentation":"poll_device_code_tokens received a non-success token response whose body parsed as an OAuth error JSON; after handling slow_down, access_denied and expired_token specially, every other error code lands here with the HTTP status and the error_description (falling back to the error code). Typical culprits are invalid_grant (code already consumed/stale) or validation errors from a malformed request.","triggerScenarios":"Re-using or re-submitting a device code, a code_verifier mismatch (PKCE), or an IdP validation error during `--device-code` login — anything that is not slow_down/access_denied/expired_token.","commonSituations":"Two terminals running login flows simultaneously and codes getting crossed, retrying a poll after a network glitch re-sends a consumed code, or OpenAI changing validation rules for the device grant.","solutions":["Use the error_description in the message: invalid_grant usually means the code was consumed or superseded — restart `auth login --device-code` and use only the newest code","Ensure only one login flow runs per machine/state-dir at a time","For persistent validation errors, capture the status+body and report; then fall back to the browser loopback flow"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match openai_oauth::poll_device_code_tokens(&client, &device).await {\n    Err(e) => {\n        let msg = e.to_string();\n        if msg.contains(\"invalid_grant\") {\n            anyhow::bail!(\"device code consumed or stale — restart the login flow\");\n        }\n        Err(e)\n    }\n    ok => ok,\n}","preventionTips":["Run exactly one device login per state dir at a time so codes never get crossed","Log the error_description — it is the authoritative cause from the IdP"],"tags":["oauth2","device-code","openai","http-status","invalid-grant"],"backgroundTag":"oauth-device-authorization-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}