{"record":{"id":"483551b96f2ca5b6","repo":"router-for-me/CLIProxyAPI","slug":"xai-device-token-error-s-s","errorCode":null,"errorMessage":"xai device token error: %s: %s","messagePattern":"xai device token error: (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"internal/auth/xai/xai.go","lineNumber":313,"sourceCode":"\tif err = json.Unmarshal(body, &payload); err != nil {\n\t\treturn nil, fmt.Errorf(\"xai device token: parse response: %w\", err), interval, false\n\t}\n\n\tif payload.Error != \"\" {\n\t\tswitch payload.Error {\n\t\tcase \"authorization_pending\":\n\t\t\treturn nil, nil, interval, true\n\t\tcase \"slow_down\":\n\t\t\tnextInterval := interval + defaultPollInterval\n\t\t\treturn nil, nil, nextInterval, true\n\t\tcase \"expired_token\":\n\t\t\treturn nil, fmt.Errorf(\"xai device code expired\"), interval, false\n\t\tcase \"access_denied\":\n\t\t\treturn nil, fmt.Errorf(\"xai device authorization denied\"), interval, false\n\t\tdefault:\n\t\t\tdesc := strings.TrimSpace(payload.ErrorDescription)\n\t\t\tif desc != \"\" {\n\t\t\t\treturn nil, fmt.Errorf(\"xai device token error: %s: %s\", payload.Error, desc), interval, false\n\t\t\t}\n\t\t\treturn nil, fmt.Errorf(\"xai device token error: %s\", payload.Error), interval, false\n\t\t}\n\t}\n\n\tif resp.StatusCode != http.StatusOK {\n\t\treturn nil, fmt.Errorf(\"xai device token request failed with status %d: %s\", resp.StatusCode, strings.TrimSpace(string(body))), interval, false\n\t}\n\tif strings.TrimSpace(payload.AccessToken) == \"\" {\n\t\treturn nil, fmt.Errorf(\"xai device token response missing access_token\"), interval, false\n\t}\n\n\temail, subject := parseJWTIdentity(payload.IDToken)\n\treturn buildTokenData(payload.AccessToken, payload.RefreshToken, payload.IDToken, payload.TokenType, payload.ExpiresIn, email, subject), nil, interval, false\n}\n\n// RefreshTokens refreshes an xAI access token.\nfunc (a *XAIAuth) RefreshTokens(ctx context.Context, refreshToken, tokenEndpoint string) (*TokenData, error) {","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/router-for-me/CLIProxyAPI/blob/78f0c4079e3e6273d65d03b5549cffc898703264/internal/auth/xai/xai.go#L295-L331","documentation":"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.","triggerScenarios":"JSON payload like {\"error\":\"invalid_client\",\"error_description\":\"client not registered for device flow\"} from the token exchange POST.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"device token error:\") {\n    code := extractOAuthErrorCode(err) // parse the code from the message\n    if code == \"temporarily_unavailable\" {\n        time.Sleep(backoff)\n        return restartDeviceFlow(ctx)\n    }\n    return fmt.Errorf(\"xAI OAuth rejected the exchange (code=%s): %w\", code, err)\n}","preventionTips":["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"],"tags":["oauth","xai","auth","api-error"],"backgroundTag":null,"analyzedSha":"78f0c4079e3e6273d65d03b5549cffc898703264","analyzedAt":"2026-08-15T12:26:37.444Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}