mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-25 00:51:20 +00:00
fix(auth): parse OpenAI nested error shape in Codex token refresh
OpenAI's OAuth token endpoint returns errors in a nested shape —
{"error": {"code": "refresh_token_reused", "message": "..."}} —
not the OAuth spec's flat {"error": "...", "error_description": "..."}.
The existing parser only handled the flat shape, so:
- `err.get("error")` returned a dict, the `isinstance(str)` guard
rejected it, and `code` stayed `"codex_refresh_failed"`.
- The dedicated `refresh_token_reused` branch (with its actionable
"re-run codex + hermes auth" message and `relogin_required=True`)
never fired.
- Users saw the generic "Codex token refresh failed with status 401"
when another Codex client (CLI, VS Code extension) had consumed
their single-use refresh token — giving no hint that re-auth was
required.
Parse both shapes, mapping OpenAI's nested `code`/`type` onto the
existing `code` variable so downstream branches (`refresh_token_reused`,
`invalid_grant`, etc.) fire correctly.
Add regression tests covering:
- nested `refresh_token_reused` → actionable message + relogin_required
- nested generic code → code + message surfaced
- flat OAuth-spec `invalid_grant` still handled (back-compat)
- unparseable body → generic fallback message, relogin_required=False
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
227afcd80f
commit
f76df30e08
2 changed files with 136 additions and 6 deletions
|
|
@ -1547,12 +1547,21 @@ def refresh_codex_oauth_pure(
|
|||
try:
|
||||
err = response.json()
|
||||
if isinstance(err, dict):
|
||||
err_code = err.get("error")
|
||||
if isinstance(err_code, str) and err_code.strip():
|
||||
code = err_code.strip()
|
||||
err_desc = err.get("error_description") or err.get("message")
|
||||
if isinstance(err_desc, str) and err_desc.strip():
|
||||
message = f"Codex token refresh failed: {err_desc.strip()}"
|
||||
err_obj = err.get("error")
|
||||
# OpenAI shape: {"error": {"code": "...", "message": "...", "type": "..."}}
|
||||
if isinstance(err_obj, dict):
|
||||
nested_code = err_obj.get("code") or err_obj.get("type")
|
||||
if isinstance(nested_code, str) and nested_code.strip():
|
||||
code = nested_code.strip()
|
||||
nested_msg = err_obj.get("message")
|
||||
if isinstance(nested_msg, str) and nested_msg.strip():
|
||||
message = f"Codex token refresh failed: {nested_msg.strip()}"
|
||||
# OAuth spec shape: {"error": "code_str", "error_description": "..."}
|
||||
elif isinstance(err_obj, str) and err_obj.strip():
|
||||
code = err_obj.strip()
|
||||
err_desc = err.get("error_description") or err.get("message")
|
||||
if isinstance(err_desc, str) and err_desc.strip():
|
||||
message = f"Codex token refresh failed: {err_desc.strip()}"
|
||||
except Exception:
|
||||
pass
|
||||
if code in {"invalid_grant", "invalid_token", "invalid_request"}:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue