{"record":{"id":"a706d13693ccaacb","repo":"zeroclaw-labs/zeroclaw","slug":"openai-device-code-expired","errorCode":null,"errorMessage":"OpenAI device-code expired","messagePattern":"OpenAI device-code expired","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"warning","filePath":"crates/zeroclaw-providers/src/auth/openai_oauth.rs","lineNumber":213,"sourceCode":"        }\n\n        let status = response.status();\n        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\",","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/auth/openai_oauth.rs#L195-L231","documentation":"The token endpoint returned the OAuth error expired_token during device-code polling: the device code (and its user_code) exceeded its expires_in lifetime before authorization completed. This is the server-side counterpart of the client-side timeout (error 693) — here OpenAI itself declares the code dead.","triggerScenarios":"Polling continues (e.g. the elapsed check at the top of the loop has not tripped due to clock skew or a slow first poll) when the server reports the device code already expired — typically a user who started authorization far too late.","commonSituations":"Delayed approvals on headless machines, expired code pasted from an old terminal scrollback, or system clock drift between client and server.","solutions":["Start a fresh `zeroclaw auth login --model-provider openai-codex --device-code` and complete authorization within the displayed window","Verify the machine clock is correct (NTP sync) so client and server lifetimes agree","Prefer the browser loopback flow when approval latency is unpredictable"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match openai_oauth::poll_device_code_tokens(&client, &device).await {\n    Err(e) if e.to_string().contains(\"device-code expired\") => {\n        // server declared the code dead: fresh flow required\n        start_device_code_flow(&client, &id, &secret, &scopes).await\n    }\n    other => other,\n}","preventionTips":["Keep system clocks NTP-synced so client and server lifetimes agree","Never re-enter a user_code from an older attempt","Complete approval in one sitting after starting the device flow"],"tags":["oauth2","device-code","openai","expired"],"backgroundTag":"oauth-device-code-expired","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}