zeroclaw-labs/zeroclaw · error · anyhow::Error
xAI device-code polling failed ({status}): {text}
Error message
xAI device-code polling failed ({status}): {text} What it means
Fallback inside `poll_device_code_tokens`: the token endpoint returned non-2xx and the body did not parse as a `{error, error_description}` JSON document, so the raw body text is embedded with the status. This shape points at infrastructure (proxies, gateways, provider incidents) rather than OAuth semantics.
Source
Thrown at crates/zeroclaw-providers/src/auth/xai_oauth.rs:317
let text = response.text().await.unwrap_or_default();
if let Ok(err) = serde_json::from_str::<OAuthErrorResponse>(&text) {
match err.error.as_str() {
"authorization_pending" => continue,
"slow_down" => {
interval_secs = interval_secs.saturating_add(5);
continue;
}
"access_denied" | "authorization_denied" => {
anyhow::bail!("xAI device-code authorization was denied")
}
"expired_token" => anyhow::bail!("xAI device-code expired"),
_ => anyhow::bail!(
"xAI device-code polling failed ({status}): {}",
err.error_description.unwrap_or(err.error)
),
}
}
anyhow::bail!("xAI device-code polling failed ({status}): {text}");
}
}
async fn parse_token_response(response: reqwest::Response) -> Result<TokenSet> {
let status = response.status();
let body = response.text().await.unwrap_or_default();
if !status.is_success() {
if let Ok(err) = serde_json::from_str::<OAuthErrorResponse>(&body) {
anyhow::bail!(
"xAI OAuth token request failed ({status}): {}",
err.error_description.unwrap_or(err.error)
);
}
anyhow::bail!("xAI OAuth token request failed ({status}): {body}");
}
let parsed: TokenResponse =
serde_json::from_str(&body).context("Failed to parse xAI OAuth token response")?;View on GitHub (pinned to 88bb9c8533)
Solutions
- Retry with backoff — transient 5xx and proxy errors dominate this path
- If the embedded text is HTML, identify the intercepting appliance and exempt auth.x.ai
- Compare a direct `curl` to the token endpoint from the same host to isolate the middleman
Defensive patterns
Strategy: retry
Try / catch
match poll_device_code_tokens(&client, &ep, &device).await {
Ok(t) => t,
Err(e) if e.to_string().contains("xAI device-code polling failed") && !has_oauth_error_code(&e) => {
retry_with_backoff(poll_device_code_tokens(&client, &ep, &device)).await? // HTML/5xx: transient path
}
Err(e) => return Err(e),
} Prevention
- Exempt auth.x.ai from TLS-inspecting proxies
- Retry with jitter — non-JSON error bodies are usually intermediary pages
- Capture status and embedded body for diagnostics before retrying
When it happens
Trigger: 5xx from xAI or an intermediary; an HTML error page from a proxy or captive portal; truncated or oversized bodies that fail JSON parsing.
Common situations: Corporate TLS-inspecting proxies rewriting responses; provider incidents; flaky egress paths.
Related errors
- xAI device-code polling failed ({status}): {}
- xAI device-code start failed ({status}): {body}
- xAI OAuth token request failed ({status}): {body}
- xAI OAuth discovery failed ({status}): {body}
- xAI device-code flow timed out before authorization complete
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/4d7abcc071f68755.
Report an issue: GitHub.