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

  1. Read the surfaced error code and description — they name the exact server-side reason
  2. For invalid_client/unauthorized_client, verify the ClientID constant in internal/auth/xai against current xAI app registration
  3. 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

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


AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15). Data as JSON: /api/errors/483551b96f2ca5b6. Report an issue: GitHub.