zeroclaw-labs/zeroclaw · error · anyhow::Error

xAI OAuth token request failed ({status}): {body}

Error message

xAI OAuth token request failed ({status}): {body}

What it means

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.

Source

Thrown at crates/zeroclaw-providers/src/auth/xai_oauth.rs:331

                    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")?;
    let expires_at = parsed
        .expires_in
        .map(|secs| Utc::now() + chrono::Duration::seconds(secs))
        .or_else(|| derive_expires_at_from_jwt(&parsed.access_token));

    Ok(TokenSet {
        access_token: parsed.access_token,
        refresh_token: parsed.refresh_token,
        id_token: parsed.id_token,
        expires_at,
        token_type: parsed.token_type.or_else(|| Some("Bearer".into())),
        scope: parsed.scope,
    })
}

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. If the body is empty or HTML, suspect the network path — `curl` the token endpoint to compare
  2. Retry with backoff for 5xx-style responses
  3. Capture the exact embedded body before escalating to the provider; it identifies the middleman
Defensive patterns

Strategy: retry

Try / catch

match refresh_access_token(&client, &refresh).await {
    Ok(t) => t,
    Err(e) if e.to_string().contains("xAI OAuth token request failed") && !is_known_oauth_error(&e) => {
        retry_with_backoff(refresh_access_token(&client, &refresh)).await? // non-JSON body: suspect the path
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: An empty body with an error status; HTML returned by proxies, CDNs, or captive portals; malformed or truncated provider responses.

Common situations: TLS-intercepting middleboxes answering for auth.x.ai; provider incidents returning gateway pages; broken egress NAT.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/8ba3140973a565cc. Report an issue: GitHub.