router-for-me/CLIProxyAPI · error
xai device token error: %s: %s
Error message
xai device token error: %s: %s
What it means
The token endpoint returned a non-standard OAuth error code with a non-empty error_description. Any error value outside authorization_pending/slow_down/expired_token/access_denied lands here and both the code and description are surfaced.
Source
Thrown at internal/auth/xai/xai.go:313
if err = json.Unmarshal(body, &payload); err != nil {
return nil, fmt.Errorf("xai device token: parse response: %w", err), interval, false
}
if payload.Error != "" {
switch payload.Error {
case "authorization_pending":
return nil, nil, interval, true
case "slow_down":
nextInterval := interval + defaultPollInterval
return nil, nil, nextInterval, true
case "expired_token":
return nil, fmt.Errorf("xai device code expired"), interval, false
case "access_denied":
return nil, fmt.Errorf("xai device authorization denied"), interval, false
default:
desc := strings.TrimSpace(payload.ErrorDescription)
if desc != "" {
return nil, fmt.Errorf("xai device token error: %s: %s", payload.Error, desc), interval, false
}
return nil, fmt.Errorf("xai device token error: %s", payload.Error), interval, false
}
}
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("xai device token request failed with status %d: %s", resp.StatusCode, strings.TrimSpace(string(body))), interval, false
}
if strings.TrimSpace(payload.AccessToken) == "" {
return nil, fmt.Errorf("xai device token response missing access_token"), interval, false
}
email, subject := parseJWTIdentity(payload.IDToken)
return buildTokenData(payload.AccessToken, payload.RefreshToken, payload.IDToken, payload.TokenType, payload.ExpiresIn, email, subject), nil, interval, false
}
// RefreshTokens refreshes an xAI access token.
func (a *XAIAuth) RefreshTokens(ctx context.Context, refreshToken, tokenEndpoint string) (*TokenData, error) {View on GitHub (pinned to 78f0c4079e)
Solutions
- Read the surfaced error code and description — they name the exact server-side reason
- For invalid_client/unauthorized_client, verify the ClientID constant in internal/auth/xai against current xAI app registration
- For scope errors, check which scopes the device flow requests
Defensive patterns
Strategy: try-catch
Try / catch
if err != nil && strings.Contains(err.Error(), "device token error:") {
code := extractOAuthErrorCode(err) // parse the code from the message
if code == "temporarily_unavailable" {
time.Sleep(backoff)
return restartDeviceFlow(ctx)
}
return fmt.Errorf("xAI OAuth rejected the exchange (code=%s): %w", code, err)
} Prevention
- Parse the OAuth error code from the message and branch on it rather than treating all errors alike
- Keep the ClientID in sync with the xAI app registration to avoid invalid_client
When it happens
Trigger: JSON payload like {"error":"invalid_client","error_description":"client not registered for device flow"} from the token exchange POST.
Common situations: ClientID constant no longer valid or not allowlisted for the device grant; server-side policy errors (invalid_scope, unauthorized_client); xAI introducing new error codes.
Related errors
- xai device token error: %s
- xai device code: response missing device_code
- xai device code: response missing user_code
- xai device code: response missing verification URI
- xai device token request failed with status %d: %s
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/483551b96f2ca5b6.
Report an issue: GitHub.