router-for-me/CLIProxyAPI · error
xai device token response missing access_token
Error message
xai device token response missing access_token
What it means
The exchange technically succeeded (no error field, status 200) but access_token is empty, which the client treats as a hard failure since TokenData cannot be built without it. This indicates a malformed or surprising success response from the token endpoint.
Source
Thrown at internal/auth/xai/xai.go:323
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) {
if strings.TrimSpace(refreshToken) == "" {
return nil, fmt.Errorf("xai token refresh: refresh token is required")
}
if ctx == nil {
ctx = context.Background()
}
refreshToken = strings.TrimSpace(refreshToken)
if strings.TrimSpace(tokenEndpoint) == "" {
discovery, errDiscover := a.Discover(ctx)
if errDiscover != nil {View on GitHub (pinned to 78f0c4079e)
Solutions
- Log the full body to see what the 'success' response actually contained
- Confirm via discovery that the token endpoint is the real OAuth token URL
- If xAI changed field names, update the payload struct json tags in exchangeDeviceCode
Defensive patterns
Strategy: try-catch
Try / catch
if err != nil && strings.Contains(err.Error(), "missing access_token") {
log.Errorf("token endpoint returned 200 without access_token; verify endpoint URL and xAI schema: %v", err)
return err
} Prevention
- Use only discovery-derived token endpoints
- Contract-test the token response shape after library or provider upgrades
When it happens
Trigger: 200 JSON from the token endpoint lacking access_token — e.g. {"token_type":"Bearer"} or an unrelated JSON object.
Common situations: Wrong endpoint that returns 200 JSON for everything; response schema change by xAI; a proxy returning a success-shaped health-check body.
Related errors
- xai device code: response missing device_code
- xai device code: response missing user_code
- xai device code: response missing verification URI
- xai device token error: %s: %s
- xai device token error: %s
AI-assisted analysis of router-for-me/CLIProxyAPI@78f0c4079e (2026-08-15).
Data as JSON: /api/errors/96c442001e44a589.
Report an issue: GitHub.