From 3b6f57fa6691897212dd80ec4e4d7eb56befc7c0 Mon Sep 17 00:00:00 2001 From: xxxigm Date: Sat, 16 May 2026 16:20:05 +0700 Subject: [PATCH] fix(run-agent): treat any 403 on xai-oauth as entitlement to stop refresh-loop The existing ``_is_entitlement_failure`` heuristic only fires when the response body contains specific substrings ("do not have an active Grok subscription", etc.). xAI has been seen to 403 standard SuperGrok subscribers with a terser body that doesn't match those keywords (#26847), and the recovery path would then mint a fresh token, get a fresh 403, and loop until Ctrl+C. Add a defense-in-depth check at the recovery call site: any 403 on ``provider == "xai-oauth"`` short-circuits ``try_refresh_current`` so the error surfaces immediately with the friendly hint from ``_summarize_api_error``. Keeps the existing keyword path for all other providers untouched. --- agent/agent_runtime_helpers.py | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/agent/agent_runtime_helpers.py b/agent/agent_runtime_helpers.py index 8e5b81ce27..56f4e5ba3a 100644 --- a/agent/agent_runtime_helpers.py +++ b/agent/agent_runtime_helpers.py @@ -606,7 +606,22 @@ def recover_with_credential_pool( return False, True if effective_reason == FailoverReason.auth: - if agent._is_entitlement_failure(error_context, status_code): + # Subscription/entitlement 403s look like auth failures on the wire + # but refresh cannot fix them — the OAuth token is already valid, + # the account simply lacks the entitlement. Without this guard, + # ``try_refresh_current()`` keeps minting fresh tokens against the + # same unsubscribed account and the main agent loop spins re-issuing + # the same 403 until the user Ctrl+C's. + # + # Defense-in-depth for #26847: xAI's backend has been seen to 403 + # standard SuperGrok subscribers with bodies that don't match the + # existing entitlement keyword set in ``_is_entitlement_failure``. + # Any 403 against ``xai-oauth`` is treated as entitlement here so + # the refresh loop can't spin in those cases either. + is_entitlement = agent._is_entitlement_failure(error_context, status_code) + if not is_entitlement and status_code == 403 and (agent.provider or "") == "xai-oauth": + is_entitlement = True + if is_entitlement: _ra().logger.info( "Credential %s — entitlement-shaped 403 from %s; " "skipping pool refresh (account lacks subscription, "