mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-05-30 06:41:51 +00:00
fix(xai-oauth): split 403 (tier/entitlement) from 400/401 in token endpoint
xAI's token endpoint returns HTTP 403 to the OAuth grant when the account isn't on the allowlist for API access (e.g. standard SuperGrok subscribers — see #26847). Treating it like a stale-token 400/401 made ``format_auth_error`` append "Run ``hermes model`` to re-authenticate", which is misleading because re-login can't change xAI's tier decision. Split 403 off in both ``refresh_xai_oauth_pure`` and the loopback login token exchange: * New error code ``xai_oauth_tier_denied`` with ``relogin_required=False`` * Message explains the entitlement gate and points at the ``XAI_API_KEY`` + ``provider: xai`` fallback * 400/401 still set ``relogin_required=True`` as before * 5xx still set ``relogin_required=False`` as before
This commit is contained in:
parent
ea49b38625
commit
60ef368792
1 changed files with 42 additions and 1 deletions
|
|
@ -3443,12 +3443,34 @@ def refresh_xai_oauth_pure(
|
|||
)
|
||||
if response.status_code != 200:
|
||||
detail = response.text.strip()
|
||||
# ``403`` from xAI's token endpoint is almost always a tier /
|
||||
# entitlement gate (the OAuth grant exists but the account isn't
|
||||
# on the allowlist for API access). Re-running ``hermes model``
|
||||
# won't fix that — surface a separate error code so
|
||||
# ``format_auth_error`` doesn't append a misleading
|
||||
# re-authenticate hint, and point users at the ``XAI_API_KEY``
|
||||
# fallback. See #26847.
|
||||
if response.status_code == 403:
|
||||
raise AuthError(
|
||||
"xAI token refresh failed with HTTP 403."
|
||||
+ (f" Response: {detail}" if detail else "")
|
||||
+ " This OAuth account is not authorized for xAI API"
|
||||
" access — xAI may be restricting API/OAuth use to"
|
||||
" specific SuperGrok tiers despite the in-app"
|
||||
" subscription being active. Re-logging in won't"
|
||||
" change that; set ``XAI_API_KEY`` and switch to"
|
||||
" ``provider: xai`` (API-key path) if available, or"
|
||||
" upgrade your subscription at https://x.ai/grok.",
|
||||
provider="xai-oauth",
|
||||
code="xai_oauth_tier_denied",
|
||||
relogin_required=False,
|
||||
)
|
||||
raise AuthError(
|
||||
"xAI token refresh failed."
|
||||
+ (f" Response: {detail}" if detail else ""),
|
||||
provider="xai-oauth",
|
||||
code="xai_refresh_failed",
|
||||
relogin_required=(response.status_code in {400, 401, 403}),
|
||||
relogin_required=(response.status_code in {400, 401}),
|
||||
)
|
||||
try:
|
||||
payload = response.json()
|
||||
|
|
@ -6225,6 +6247,25 @@ def _xai_oauth_exchange_code_for_tokens(
|
|||
|
||||
if response.status_code != 200:
|
||||
body = response.text.strip()
|
||||
# See ``refresh_xai_oauth_pure`` — token-exchange 403 also
|
||||
# surfaces tier/entitlement gating from xAI's backend. Avoid
|
||||
# the misleading "re-authenticate" hint and point at the API
|
||||
# key fallback. See #26847.
|
||||
if response.status_code == 403:
|
||||
raise AuthError(
|
||||
f"xAI token exchange failed (HTTP 403)."
|
||||
+ (f" Response: {body}" if body else "")
|
||||
+ " This OAuth account is not authorized for xAI API"
|
||||
" access — xAI may be restricting API/OAuth use to"
|
||||
" specific SuperGrok tiers despite the in-app"
|
||||
" subscription being active. Set ``XAI_API_KEY``"
|
||||
" and switch to ``provider: xai`` (API-key path) if"
|
||||
" available, or upgrade your subscription at"
|
||||
" https://x.ai/grok.",
|
||||
provider="xai-oauth",
|
||||
code="xai_oauth_tier_denied",
|
||||
relogin_required=False,
|
||||
)
|
||||
raise AuthError(
|
||||
f"xAI token exchange failed (HTTP {response.status_code})."
|
||||
+ (f" Response: {body}" if body else ""),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue