Skip to content

[Bug]: Codex usage_limit_reached 429 retries exhausted pool credential once before rotating #26388

Description

@Qwinty

Bug Description

OpenAI Codex can return HTTP 429 with a structured error body like:

{
  "error": {
    "type": "usage_limit_reached",
    "message": "The usage limit has been reached"
  }
}

Hermes currently extracts only error.code / error.error into the credential-pool error context, so error.type=usage_limit_reached is lost. The central classifier sees HTTP 429 and treats it as a generic transient rate_limit.

That makes _recover_with_credential_pool() keep the same exhausted Codex credential on the first failure and only rotate after a second 429 in the same retry sequence. For Codex account usage windows this is not useful: the current OAuth profile is exhausted until reset, while other pool entries may still have available quota.

Steps to Reproduce

  1. Configure openai-codex with two or more OAuth entries in the credential pool.
  2. Use an entry whose Codex quota is exhausted while another pool entry still has quota.
  3. Trigger a Codex request that returns HTTP 429 with error.type = "usage_limit_reached".
  4. Observe the first recovery attempt retrying the same exhausted credential instead of marking it exhausted and rotating immediately.

A minimal unit repro is _recover_with_credential_pool(status_code=429, has_retried_429=False, error_context={"reason": "usage_limit_reached"}): today it returns (False, True) instead of rotating.

Expected Behavior

A Codex usage_limit_reached 429 should be treated as account/window exhaustion for pool recovery. Hermes should mark that pool entry exhausted and rotate to the next available same-provider credential immediately.

Actual Behavior

Hermes treats the response as a generic transient 429, retries the same credential once, and can appear stuck on an exhausted account even when hermes auth list openai-codex shows other accounts without limits.

Affected Component

Agent Core (conversation loop, context compression, memory)

Messaging Platform (if gateway-related)

Telegram and CLI can both hit the same core recovery path; the bug is in run_agent.py.

Debug Report

N/A for this report. This was reduced to the recovery helper and covered with unit tests in the companion PR.

Operating System

Ubuntu 24.04

Python Version

Python 3.11+

Hermes Version

main at d541628

Additional Logs / Traceback (optional)

Known provider message:

HTTP 429: The usage limit has been reached

Known structured body field that is currently dropped:

error.type = usage_limit_reached

Root Cause Analysis (optional)

Two details combine:

  1. AIAgent._extract_api_error_context() ignores payload["type"], so OpenAI's usage_limit_reached type does not reach the pool recovery code.
  2. _recover_with_credential_pool() treats all 429s as transient FailoverReason.rate_limit, where the first 429 intentionally retries the same credential.

That first retry makes sense for throttling, but not for Codex usage_limit_reached, which is a quota-window exhaustion signal for the current account.

Similar Issues / PRs Checked

This is intentionally narrower than the currently open related work:

Searches included usage_limit_reached with first 429, second 429, retry same credential, rotate immediately, and The usage limit has been reached + credential pool across open and closed issues/PRs.

Proposed Fix (optional)

  • Extract payload["type"] as the context reason when code is absent.
  • In rate-limit pool recovery, if error_context.reason contains usage_limit_reached or the message contains usage limit has been reached, skip the first-same-credential retry and immediately call mark_exhausted_and_rotate().
  • Add regression tests for both context extraction and immediate rotation.

Are you willing to submit a PR for this?

Yes; companion PR follows.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P2Medium — degraded but workaround existsarea/authAuthentication, OAuth, credential poolscomp/agentCore agent runtime: loop, agent_init, prompt builder, context-compression, responses endpointprovider/openaiOpenAI / Codex Responses APItype/bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions