Skip to content

fix(gateway): classify Codex 429 quota as rate-limit, not missing credentials - #33168

Merged
teknium1 merged 2 commits into
mainfrom
hermes/hermes-5bf34d29
May 27, 2026
Merged

fix(gateway): classify Codex 429 quota as rate-limit, not missing credentials#33168
teknium1 merged 2 commits into
mainfrom
hermes/hermes-5bf34d29

Conversation

@teknium1

@teknium1 teknium1 commented May 27, 2026

Copy link
Copy Markdown
Contributor

Salvage of #33080 (@konsisumer) onto current main.

Summary

When the Codex OAuth token endpoint returns 429 (usage-limit / quota exhaustion), refresh_codex_oauth_pure raised a generic auth error. The gateway caught it as an AuthError and surfaced Primary provider auth failed: No Codex credentials stored. Run \hermes auth`` to the operator and to the chat reply — misleading, because the stored credentials are valid and re-authenticating cannot lift a usage cap.

This PR separates error classification (a 429 is a transient rate-limit/quota cap) from remediation copy ("re-authenticate"):

  • 429 is now classified distinctly (code=codex_rate_limited, relogin_required=False) with a non-alarming message that honors Retry-After
  • Gateway logs it as Primary provider rate-limited (429) instead of "auth failed"
  • User-facing formatter no longer appends the re-auth instruction
  • Fallback-resolution log now prints the literal provider key from config (e.g. ollama) instead of swallowing it

Changes

  • gateway/run.py: classify 429 as rate-limit at the gateway error-formatting layer
  • hermes_cli/auth.py: new codex_rate_limited error code; refresh_codex_oauth_pure raises with explicit classification
  • tests/hermes_cli/test_auth_codex_provider.py: regression coverage for the 429-vs-401 distinction

Validation

  • 20/20 passing in tests/hermes_cli/test_auth_codex_provider.py

Attribution

Cherry-picked from @konsisumer's #33080 (clean cherry-pick, no conflicts against current main after #33164 also landed).


Follow-on: also fix pre-existing test_verbose_command failures

Surfaced during CI on #33164 — two tests in tests/gateway/test_verbose_command.py had stale assertions about Telegram's tool_progress default. The default was changed from "new" to "off" (tier-1 inbox preset in gateway/display_config.py keeping mobile chats final-answer-first), but the tests still expected the old cycle behavior (new → all). Updated to match current behavior (off → new).

This is a zero-risk test-only fix unrelated to the Codex 429 classification — surfacing it here so the PR's CI goes green rather than carrying the pre-existing failure as a known-bad signal.

Infographic

codex-429-rate-limit-classification

…dentials

When the Codex OAuth token endpoint returns 429 (usage-limit / quota
exhaustion), refresh_codex_oauth_pure raised a generic auth error that the
gateway surfaced as 'Primary provider auth failed: No Codex credentials
stored. Run hermes auth', prompting re-auth that cannot lift a quota cap.

Classify 429 distinctly (codex_rate_limited, relogin_required=False) with a
non-alarming quota message that honors Retry-After, log it as
'Primary provider rate-limited (429)', and stop format_auth_error from
appending the re-authenticate remediation. Also log the fallback provider's
literal config key instead of the resolved runtime category.

Refs #32790
@github-actions

github-actions Bot commented May 27, 2026

Copy link
Copy Markdown
Contributor

🔎 Lint report: hermes/hermes-5bf34d29 vs origin/main

ruff

Total: 0 on HEAD, 0 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 0 pre-existing issues carried over.

ty (type checker)

Total: 9493 on HEAD, 9493 on base (➖ 0)

🆕 New issues: none

✅ Fixed issues: none

Unchanged: 5013 pre-existing issues carried over.

Diagnostics are surfaced as warnings — this check never fails the build.

Two tests in test_verbose_command.py asserted Telegram's tool_progress
default was "new" and expected /verbose to cycle that to "all". The
default has since been overridden to "off" in gateway/display_config.py
(_PLATFORM_DEFAULTS for telegram — tier-1 inbox preset that keeps mobile
chats final-answer-first), making the first /verbose invocation cycle
off → new, not all → verbose.

The behavioral change was intentional; the tests were stale and missing
from the same commit. Surfaced as a pre-existing failure on origin/main
during CI for the unrelated #33164 / #33168 Codex auth salvages.
Comment thread gateway/run.py Dismissed
@teknium1
teknium1 merged commit 0b6ace6 into main May 27, 2026
25 of 26 checks passed
@teknium1
teknium1 deleted the hermes/hermes-5bf34d29 branch May 27, 2026 10:13
@alt-glitch alt-glitch added type/bug Something isn't working P3 Low — cosmetic, nice to have comp/gateway Gateway runner, session dispatch, delivery provider/openai OpenAI / Codex Responses API codex labels May 27, 2026
mathias3 pushed a commit to mathias3/hermes-agent that referenced this pull request May 28, 2026
Two tests in test_verbose_command.py asserted Telegram's tool_progress
default was "new" and expected /verbose to cycle that to "all". The
default has since been overridden to "off" in gateway/display_config.py
(_PLATFORM_DEFAULTS for telegram — tier-1 inbox preset that keeps mobile
chats final-answer-first), making the first /verbose invocation cycle
off → new, not all → verbose.

The behavioral change was intentional; the tests were stale and missing
from the same commit. Surfaced as a pre-existing failure on origin/main
during CI for the unrelated NousResearch#33164 / NousResearch#33168 Codex auth salvages.
Bryce-huang pushed a commit to wbkunlun/hermes-agent that referenced this pull request May 29, 2026
Two tests in test_verbose_command.py asserted Telegram's tool_progress
default was "new" and expected /verbose to cycle that to "all". The
default has since been overridden to "off" in gateway/display_config.py
(_PLATFORM_DEFAULTS for telegram — tier-1 inbox preset that keeps mobile
chats final-answer-first), making the first /verbose invocation cycle
off → new, not all → verbose.

The behavioral change was intentional; the tests were stale and missing
from the same commit. Surfaced as a pre-existing failure on origin/main
during CI for the unrelated NousResearch#33164 / NousResearch#33168 Codex auth salvages.

#AI commit#
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
Two tests in test_verbose_command.py asserted Telegram's tool_progress
default was "new" and expected /verbose to cycle that to "all". The
default has since been overridden to "off" in gateway/display_config.py
(_PLATFORM_DEFAULTS for telegram — tier-1 inbox preset that keeps mobile
chats final-answer-first), making the first /verbose invocation cycle
off → new, not all → verbose.

The behavioral change was intentional; the tests were stale and missing
from the same commit. Surfaced as a pre-existing failure on origin/main
during CI for the unrelated NousResearch#33164 / NousResearch#33168 Codex auth salvages.
alt-glitch pushed a commit that referenced this pull request Jun 14, 2026
Two tests in test_verbose_command.py asserted Telegram's tool_progress
default was "new" and expected /verbose to cycle that to "all". The
default has since been overridden to "off" in gateway/display_config.py
(_PLATFORM_DEFAULTS for telegram — tier-1 inbox preset that keeps mobile
chats final-answer-first), making the first /verbose invocation cycle
off → new, not all → verbose.

The behavioral change was intentional; the tests were stale and missing
from the same commit. Surfaced as a pre-existing failure on origin/main
during CI for the unrelated #33164 / #33168 Codex auth salvages.
T02200059 pushed a commit to T02200059/hermes-agent that referenced this pull request Jun 18, 2026
Two tests in test_verbose_command.py asserted Telegram's tool_progress
default was "new" and expected /verbose to cycle that to "all". The
default has since been overridden to "off" in gateway/display_config.py
(_PLATFORM_DEFAULTS for telegram — tier-1 inbox preset that keeps mobile
chats final-answer-first), making the first /verbose invocation cycle
off → new, not all → verbose.

The behavioral change was intentional; the tests were stale and missing
from the same commit. Surfaced as a pre-existing failure on origin/main
during CI for the unrelated NousResearch#33164 / NousResearch#33168 Codex auth salvages.
xyshanren pushed a commit to xyshanren/hermes-agent-cn that referenced this pull request Jun 25, 2026
Two tests in test_verbose_command.py asserted Telegram's tool_progress
default was "new" and expected /verbose to cycle that to "all". The
default has since been overridden to "off" in gateway/display_config.py
(_PLATFORM_DEFAULTS for telegram — tier-1 inbox preset that keeps mobile
chats final-answer-first), making the first /verbose invocation cycle
off → new, not all → verbose.

The behavioral change was intentional; the tests were stale and missing
from the same commit. Surfaced as a pre-existing failure on origin/main
during CI for the unrelated NousResearch#33164 / NousResearch#33168 Codex auth salvages.
waefrebeorn pushed a commit to waefrebeorn/slermes that referenced this pull request Jul 2, 2026
Two tests in test_verbose_command.py asserted Telegram's tool_progress
default was "new" and expected /verbose to cycle that to "all". The
default has since been overridden to "off" in gateway/display_config.py
(_PLATFORM_DEFAULTS for telegram — tier-1 inbox preset that keeps mobile
chats final-answer-first), making the first /verbose invocation cycle
off → new, not all → verbose.

The behavioral change was intentional; the tests were stale and missing
from the same commit. Surfaced as a pre-existing failure on origin/main
during CI for the unrelated NousResearch#33164 / NousResearch#33168 Codex auth salvages.
santhreal pushed a commit to santhreal/hermes-agent that referenced this pull request Jul 13, 2026
Two tests in test_verbose_command.py asserted Telegram's tool_progress
default was "new" and expected /verbose to cycle that to "all". The
default has since been overridden to "off" in gateway/display_config.py
(_PLATFORM_DEFAULTS for telegram — tier-1 inbox preset that keeps mobile
chats final-answer-first), making the first /verbose invocation cycle
off → new, not all → verbose.

The behavioral change was intentional; the tests were stale and missing
from the same commit. Surfaced as a pre-existing failure on origin/main
during CI for the unrelated NousResearch#33164 / NousResearch#33168 Codex auth salvages.
donbowman pushed a commit to donbowman/hermes-agent that referenced this pull request Jul 13, 2026
Two tests in test_verbose_command.py asserted Telegram's tool_progress
default was "new" and expected /verbose to cycle that to "all". The
default has since been overridden to "off" in gateway/display_config.py
(_PLATFORM_DEFAULTS for telegram — tier-1 inbox preset that keeps mobile
chats final-answer-first), making the first /verbose invocation cycle
off → new, not all → verbose.

The behavioral change was intentional; the tests were stale and missing
from the same commit. Surfaced as a pre-existing failure on origin/main
during CI for the unrelated NousResearch#33164 / NousResearch#33168 Codex auth salvages.
Gravezzz pushed a commit to Gravezzz/hermes-agent that referenced this pull request Jul 21, 2026
Two tests in test_verbose_command.py asserted Telegram's tool_progress
default was "new" and expected /verbose to cycle that to "all". The
default has since been overridden to "off" in gateway/display_config.py
(_PLATFORM_DEFAULTS for telegram — tier-1 inbox preset that keeps mobile
chats final-answer-first), making the first /verbose invocation cycle
off → new, not all → verbose.

The behavioral change was intentional; the tests were stale and missing
from the same commit. Surfaced as a pre-existing failure on origin/main
during CI for the unrelated NousResearch#33164 / NousResearch#33168 Codex auth salvages.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

codex comp/gateway Gateway runner, session dispatch, delivery P3 Low — cosmetic, nice to have provider/openai OpenAI / Codex Responses API type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants