fix(auxiliary): detect xAI OAuth 403 bad-credentials as auth error#31527
fix(auxiliary): detect xAI OAuth 403 bad-credentials as auth error#31527Moikapy wants to merge 1 commit into
Conversation
affca71 to
e301d40
Compare
xAI returns HTTP 403 (not 401) with unauthenticated:bad-credentials when an OAuth2 access token has expired or is invalid. The existing _is_auth_error() only checked for 401 status codes, so these tokens were never refreshed and the 403 propagated as a generic permission denied error. Three fixes: 1. _is_auth_error: Recognize xAI's 403+bad-credentials pattern as an auth failure, triggering token refresh instead of silent failure. 2. _refresh_provider_credentials: Add xai-oauth branch with pool-level refresh (try_refresh_current with select to ensure current entry) then fallback to singleton resolver with force_refresh=True. 3. _recoverable_pool_provider: Map api.x.ai host to xai-oauth pool for auto-resolved providers, matching existing pattern for openai-codex/openrouter/nous/anthropic. Includes 14 tests covering the new detection logic, host mapping, and graceful fallback behavior. Signed-off-by: moikapy <moikapy@devmoi.com>
e301d40 to
3860872
Compare
|
Closing — merged via salvage PR #34431 (#34431) with your commit One merge conflict to resolve: Distinct from the previously-merged WKE disambiguator fix (#30872) which covered the main agent loop's recovery path in Your 14 tests covered all three functions cleanly — no follow-up test work was needed. Thanks! |
What
xAI returns HTTP 403 (not 401) with
unauthenticated:bad-credentialswhen an OAuth2 access token has expired or is invalid. The existing_is_auth_error()only matched status 401, so these tokens were never refreshed and the 403 propagated as a generic "Auxiliary title_generation failed" / "context summary failed" error.Why
Three gaps in the auxiliary client error recovery path for xAI OAuth:
_is_auth_error()— only checked HTTP 401. xAI uses 403 for expired/invalid OAuth tokens, which is semantically a 401 auth failure. The recovery system never recognized these as auth errors, so it never triggered token refresh or pool rotation._refresh_provider_credentials()— had branches foropenai-codex,nous, andanthropic, but notxai-oauth. Even if the 403 was detected as auth, the refresh function returnedFalsewithout attempting any refresh._recoverable_pool_provider()— mapped hostnames forchatgpt.com,openrouter.ai,api.anthropic.com, etc. but notapi.x.ai, so auto-resolved providers couldn't find the xAI credential pool for recovery.Changes
_is_auth_error()— Detect xAI's403 + "bad-credentials"pattern and"unauthenticated" + "bad-credentials"string pattern as auth failures._refresh_provider_credentials()— Addxai-oauthbranch: pool-level refresh viatry_refresh_current()(withselect()to ensure a current entry), then fall back toresolve_xai_oauth_runtime_credentials(force_refresh=True)._recoverable_pool_provider()— Mapapi.x.aihost to"xai-oauth"pool provider.How to test
hermes model→ select xAI Grok OAuthauxiliary.title_generation.model: grok-4.3)Unit tests:
14 tests covering detection, host mapping, and graceful fallback.
Tested on