{"record":{"id":"916f81e0cca38c8f","repo":"zeroclaw-labs/zeroclaw","slug":"openai-device-code-polling-failed-status-tex","errorCode":null,"errorMessage":"OpenAI device-code polling failed ({status}): {text}","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":224,"sourceCode":"                    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        }\n    )\n    .await\n}\n\nasync fn receive_loopback_code_inner(expected_state: &str, timeout: Duration) -> Result<String> {\n    let listener = TcpListener::bind(\"127.0.0.1:1455\")\n        .await\n        .context(\"Failed to bind callback listener at 127.0.0.1:1455\")?;","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/auth/openai_oauth.rs#L206-L242","documentation":"The catch-all branch of poll_device_code_tokens: the token poll returned a non-success status AND the body did not parse as a known OAuth error JSON (or was not an error object at all), so the raw response text is embedded in the message. This is how unexpected responses — 5xx HTML pages, gateway timeouts, proxy blocks, empty bodies — surface from the device flow.","triggerScenarios":"OpenAI token endpoint returning 500/502/503 with an HTML or empty body during an incident, or a corporate proxy/captive portal intercepting the POST during device-code login.","commonSituations":"Cloud/vendor incidents, rate-limit pages without JSON bodies, TLS-inspecting proxies rewriting responses, or DNS sinkholes.","solutions":["Inspect {status} and {text}: HTML/markup usually means proxy or incident page — check egress and https://status.openai.com","Retry the login after the incident clears; the device flow is stateless to restart","If a proxy is intercepting, add an exception for the OpenAI auth domains or use the browser loopback flow"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"let mut attempt = 0;\nloop {\n    match openai_oauth::poll_device_code_tokens(&client, &device).await {\n        Err(e) if e.to_string().contains(\"polling failed\") && attempt < 3 => {\n            attempt += 1;\n            tokio::time::sleep(Duration::from_secs(2u64.pow(attempt))).await;\n        }\n        other => break other,\n    }\n}","preventionTips":["Ensure direct egress to OpenAI auth domains; bypass intercepting proxies","Treat HTML bodies in this error as infrastructure noise, not OAuth failure","Check vendor status before retrying during incidents"],"tags":["oauth2","device-code","openai","http-status","network","proxy"],"backgroundTag":"oauth-device-authorization-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}