Hmbown/CodeWhale · error · anyhow::Error

xAI device-code token exchange failed: {detail}

Error message

xAI device-code token exchange failed: {detail}

What it means

The device-code token poll reached the token endpoint but the exchange failed with a terminal OAuth error — that is, an error other than the transient authorization_pending or slow_down signals, which are retried internally. {detail} carries the redacted failure reason; the request carried the device credential, so details are deliberately limited.

Source

Thrown at crates/tui/src/xai_oauth.rs:1286

        ("device_code", device_code),
    ];
    #[cfg(test)]
    crate::external_credentials::record_oauth_network();
    let response = client
        .post(token_endpoint)
        .form(&params)
        .send()
        .context("xAI device-code token poll failed")?;
    let (status, body): (_, TokenResponse) =
        parse_oauth_json_response(response, "xAI device-code token exchange")?;
    if let Some(err) = body.error.as_deref() {
        if matches!(err, "authorization_pending" | "slow_down") {
            bail!("{err}");
        }
        // Poll requests carry the device credential. Keep diagnostics to the
        // standard error code and HTTP status rather than echoing descriptions.
        let detail = oauth_failure_detail(Some(err), None, status);
        bail!("xAI device-code token exchange failed: {detail}");
    }
    if !status.is_success() {
        let detail = oauth_failure_detail(None, None, status);
        bail!("xAI device-code token exchange failed: {detail}");
    }
    Ok(body)
}

fn jwt_expiry_seconds(token: &str) -> Option<u64> {
    use base64::Engine as _;
    use base64::engine::general_purpose::URL_SAFE_NO_PAD;
    let mut parts = token.split('.');
    let _header = parts.next()?;
    let payload = parts.next()?;
    let decoded = URL_SAFE_NO_PAD.decode(payload).ok()?;
    let claims: Value = serde_json::from_slice(&decoded).ok()?;
    claims.get("exp")?.as_u64()
}

View on GitHub (pinned to 0c42157ee5)

Solutions

  1. Check {detail}: expired_token means the user took too long — restart device-code login
  2. access_denied means the user or xAI rejected the request; confirm and retry login
  3. Verify the client_id and device authorization are still valid, then restart the flow
  4. Fall back to XAI_API_KEY if device-code login keeps failing
Defensive patterns

Strategy: retry

When it happens

Trigger: Thrown at crates/tui/src/xai_oauth.rs:1286 when the library encounters an invalid state.

Common situations: See trigger scenarios.


AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20). Data as JSON: /api/errors/fa03a4b42246f3d3. Report an issue: GitHub.