{"record":{"id":"15ad24e4dd58bf02","repo":"zeroclaw-labs/zeroclaw","slug":"openai-device-code-start-failed-status-body","errorCode":null,"errorMessage":"OpenAI device-code start failed ({status}): {body}","messagePattern":"OpenAI device-code start failed \\((.+?)\\): (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/auth/openai_oauth.rs","lineNumber":147,"sourceCode":"}\n\npub async fn start_device_code_flow(client: &Client) -> Result<DeviceCodeStart> {\n    let form = [\n        (\"client_id\", OPENAI_OAUTH_CLIENT_ID),\n        (\"scope\", \"openid profile email offline_access\"),\n    ];\n\n    let response = client\n        .post(OPENAI_OAUTH_DEVICE_CODE_URL)\n        .form(&form)\n        .send()\n        .await\n        .context(\"Failed to start OpenAI OAuth device-code flow\")?;\n\n    if !response.status().is_success() {\n        let status = response.status();\n        let body = response.text().await.unwrap_or_default();\n        anyhow::bail!(\"OpenAI device-code start failed ({status}): {body}\");\n    }\n\n    let parsed: DeviceCodeResponse = response\n        .json()\n        .await\n        .context(\"Failed to parse OpenAI device-code response\")?;\n\n    Ok(DeviceCodeStart {\n        device_code: parsed.device_code,\n        user_code: parsed.user_code,\n        verification_uri: parsed.verification_uri,\n        verification_uri_complete: parsed.verification_uri_complete,\n        expires_in: parsed.expires_in,\n        interval: parsed.interval.unwrap_or(5).max(1),\n        message: parsed.message,\n    })\n}\n","sourceCodeStart":129,"sourceCodeEnd":165,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/auth/openai_oauth.rs#L129-L165","documentation":"start_device_code_flow POSTs to OpenAI's device authorization endpoint; the request itself completed (transport ok, hence no 'Failed to start' context error) but the HTTP status was non-2xx. The message embeds both the status code and the raw response body, which usually names the real cause (invalid client_id, blocked origin, or an upstream outage page).","triggerScenarios":"`zeroclaw auth login --model-provider openai-codex --device-code` (or automatic fallback to device flow) when the endpoint returns e.g. 400 invalid_client, 401 bad credentials, or 5xx during an OpenAI incident.","commonSituations":"Client credentials mismatch after an app rotation, corporate proxies returning HTML error pages (so the body shows markup instead of JSON), or OpenAI auth endpoint outages.","solutions":["Read the embedded body: 'invalid client' means the client_id/secret pair is wrong — check how alias_creds resolves credentials for the profile","If the body is proxy/HTML noise, fix egress (proxy, TLS inspection) and retry","Check https://status.openai.com for device-flow endpoint incidents and retry after recovery","Fall back to the browser loopback flow (omit --device-code) if device authorization is blocked in your environment"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"let resp = openai_oauth::start_device_code_flow(&client, &id, &secret, &scopes).await;\nmatch resp {\n    Err(e) => {\n        let msg = e.to_string();\n        if msg.contains(\"(400)\") || msg.contains(\"(401)\") {\n            return Err(e.context(\"device-flow credentials rejected — check client_id/secret\")); // permanent\n        }\n        tokio::time::sleep(Duration::from_secs(5)).await; // 5xx/proxy: retry\n    }\n    ok => return ok,\n}","preventionTips":["Verify client credentials resolve correctly (alias_creds) before starting device flow","Watch for proxy HTML in the embedded body — it distinguishes egress issues from real OAuth errors","Fall back to the loopback browser flow when device endpoints are blocked"],"tags":["oauth2","device-code","openai","http-status","network"],"backgroundTag":"oauth-device-authorization-failed","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}