{"record":{"id":"8ba3140973a565cc","repo":"zeroclaw-labs/zeroclaw","slug":"xai-oauth-token-request-failed-status-body","errorCode":null,"errorMessage":"xAI OAuth token request failed ({status}): {body}","messagePattern":"xAI OAuth token request failed \\((.+?)\\): (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-providers/src/auth/xai_oauth.rs","lineNumber":331,"sourceCode":"                    err.error_description.unwrap_or(err.error)\n                ),\n            }\n        }\n        anyhow::bail!(\"xAI device-code polling failed ({status}): {text}\");\n    }\n}\n\nasync fn parse_token_response(response: reqwest::Response) -> Result<TokenSet> {\n    let status = response.status();\n    let body = response.text().await.unwrap_or_default();\n    if !status.is_success() {\n        if let Ok(err) = serde_json::from_str::<OAuthErrorResponse>(&body) {\n            anyhow::bail!(\n                \"xAI OAuth token request failed ({status}): {}\",\n                err.error_description.unwrap_or(err.error)\n            );\n        }\n        anyhow::bail!(\"xAI OAuth token request failed ({status}): {body}\");\n    }\n\n    let parsed: TokenResponse =\n        serde_json::from_str(&body).context(\"Failed to parse xAI OAuth token response\")?;\n    let expires_at = parsed\n        .expires_in\n        .map(|secs| Utc::now() + chrono::Duration::seconds(secs))\n        .or_else(|| derive_expires_at_from_jwt(&parsed.access_token));\n\n    Ok(TokenSet {\n        access_token: parsed.access_token,\n        refresh_token: parsed.refresh_token,\n        id_token: parsed.id_token,\n        expires_at,\n        token_type: parsed.token_type.or_else(|| Some(\"Bearer\".into())),\n        scope: parsed.scope,\n    })\n}","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-providers/src/auth/xai_oauth.rs#L313-L349","documentation":"Companion of the structured variant in xAI's `parse_token_response`: the token endpoint returned non-2xx and the body did NOT parse as an OAuth error document, so the raw body is embedded with the status. Reached only after the `serde_json::from_str::<OAuthErrorResponse>` attempt fails.","triggerScenarios":"An empty body with an error status; HTML returned by proxies, CDNs, or captive portals; malformed or truncated provider responses.","commonSituations":"TLS-intercepting middleboxes answering for auth.x.ai; provider incidents returning gateway pages; broken egress NAT.","solutions":["If the body is empty or HTML, suspect the network path — `curl` the token endpoint to compare","Retry with backoff for 5xx-style responses","Capture the exact embedded body before escalating to the provider; it identifies the middleman"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match refresh_access_token(&client, &refresh).await {\n    Ok(t) => t,\n    Err(e) if e.to_string().contains(\"xAI OAuth token request failed\") && !is_known_oauth_error(&e) => {\n        retry_with_backoff(refresh_access_token(&client, &refresh)).await? // non-JSON body: suspect the path\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Compare a direct curl to the token endpoint when bodies look like HTML","Keep egress free of captive portals and rewriting proxies","Retry only idempotent calls (refresh); never auto-retry code exchange"],"tags":["oauth","xai","token-endpoint","http","proxy","rust"],"backgroundTag":"oauth-token-endpoint-error","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}