fix(auth): actionable error message when Codex refresh token is reused
When the Codex CLI (or VS Code extension) consumes a refresh token before Hermes can use it, Hermes previously surfaced a generic 401 error with no actionable guidance. - In `refresh_codex_oauth_pure`: detect `refresh_token_reused` from the OAuth endpoint and raise an AuthError explaining the cause and the exact steps to recover (run `codex` to refresh, then `hermes login`). - In `run_agent.py`: when provider is `openai-codex` and HTTP 401 is received, show Codex-specific recovery steps instead of the generic "check your API key" message. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1030,6 +1030,14 @@ def refresh_codex_oauth_pure(
|
||||
pass
|
||||
if code in {"invalid_grant", "invalid_token", "invalid_request"}:
|
||||
relogin_required = True
|
||||
if code == "refresh_token_reused":
|
||||
message = (
|
||||
"Codex refresh token was already consumed by another client "
|
||||
"(e.g. Codex CLI or VS Code extension). "
|
||||
"Run `codex` in your terminal to generate fresh tokens, "
|
||||
"then run `hermes login --provider openai-codex` to re-authenticate."
|
||||
)
|
||||
relogin_required = True
|
||||
raise AuthError(
|
||||
message,
|
||||
provider="openai-codex",
|
||||
|
||||
16
run_agent.py
16
run_agent.py
@@ -8187,11 +8187,17 @@ class AIAgent:
|
||||
self._vprint(f"{self.log_prefix} 🌐 Endpoint: {_base}", force=True)
|
||||
# Actionable guidance for common auth errors
|
||||
if status_code in (401, 403) or "unauthorized" in error_msg or "forbidden" in error_msg or "permission" in error_msg:
|
||||
self._vprint(f"{self.log_prefix} 💡 Your API key was rejected by the provider. Check:", force=True)
|
||||
self._vprint(f"{self.log_prefix} • Is the key valid? Run: hermes setup", force=True)
|
||||
self._vprint(f"{self.log_prefix} • Does your account have access to {_model}?", force=True)
|
||||
if "openrouter" in str(_base).lower():
|
||||
self._vprint(f"{self.log_prefix} • Check credits: https://openrouter.ai/settings/credits", force=True)
|
||||
if _provider == "openai-codex" and status_code == 401:
|
||||
self._vprint(f"{self.log_prefix} 💡 Codex OAuth token was rejected (HTTP 401). Your token may have been", force=True)
|
||||
self._vprint(f"{self.log_prefix} refreshed by another client (Codex CLI, VS Code). To fix:", force=True)
|
||||
self._vprint(f"{self.log_prefix} 1. Run `codex` in your terminal to generate fresh tokens.", force=True)
|
||||
self._vprint(f"{self.log_prefix} 2. Then run `hermes login --provider openai-codex` to re-authenticate.", force=True)
|
||||
else:
|
||||
self._vprint(f"{self.log_prefix} 💡 Your API key was rejected by the provider. Check:", force=True)
|
||||
self._vprint(f"{self.log_prefix} • Is the key valid? Run: hermes setup", force=True)
|
||||
self._vprint(f"{self.log_prefix} • Does your account have access to {_model}?", force=True)
|
||||
if "openrouter" in str(_base).lower():
|
||||
self._vprint(f"{self.log_prefix} • Check credits: https://openrouter.ai/settings/credits", force=True)
|
||||
else:
|
||||
self._vprint(f"{self.log_prefix} 💡 This type of error won't be fixed by retrying.", force=True)
|
||||
logging.error(f"{self.log_prefix}Non-retryable client error: {api_error}")
|
||||
|
||||
Reference in New Issue
Block a user