Skip to content

codex-client/retry: TransportError::RetryLimit is unreachable — retry exhaustion surfaces wrong error #23404

Closed

Description

@thesayakmondal

What issue are you seeing?

TransportError::RetryLimit is defined and matched throughout the codebase (in api_bridge.rs it becomes CodexErr::RetryLimit → ResponseTooManyFailedAttempts), but it can never actually be emitted by run_with_retry.

File: codex-rs/codex-client/src/retry.rs, lines 58–72

The loop is for attempt in 0..=policy.max_attempts (inclusive upper bound). On the final iteration where attempt == max_attempts, should_retry returns false (its own guard: if attempt >= max_attempts { return false; }), so the match falls to Err(err) => return Err(err) — returning the raw underlying error. The Err(TransportError::RetryLimit) after the loop is dead code; the loop always exits via an early return before reaching it.

Impact: After exhausting all retries, callers receive a raw Http 5xx or TransportError::Network instead of TransportError::RetryLimit. The match arm for RetryLimit in api_bridge.rs (line 122) is therefore also dead. Users never see the ResponseTooManyFailedAttempts error the system was designed to surface.

What steps can reproduce the bug?

This is a code-reading bug — no runtime reproduction needed. Read codex-rs/codex-client/src/retry.rs:

  1. run_with_retry loops for attempt in 0..=policy.max_attempts
  2. On the last iteration (attempt == max_attempts), should_retry returns false
  3. The Err(err) => return Err(err) branch fires, returning the raw error
  4. Err(TransportError::RetryLimit) at line 72 is never reached

Proposed fix (one character): Change 0..=policy.max_attempts to 0..policy.max_attempts

// Before
for attempt in 0..=policy.max_attempts {

// After  
for attempt in 0..policy.max_attempts {

This makes the loop run exactly max_attempts times, and when exhausted, falls through to Err(TransportError::RetryLimit) as intended.

What is the expected behavior?

After exhausting all retries, run_with_retry should return Err(TransportError::RetryLimit). This would then be correctly converted by api_bridge.rs into CodexErr::RetryLimit → ResponseTooManyFailedAttempts, giving users a clear, actionable error message instead of a raw 5xx or network error.

Additional information

The fix is a single character change — ..= to .. on the for loop range in run_with_retry. No other files need to change. The existing RetryLimit handling in api_bridge.rs and protocol/src/error.rs is already correct and will work properly once this is fixed.

Activity

  1. added
    CLIIssues related to the Codex CLI
    connectivityIssues involving networking or endpoint connectivity problems (disconnections)
    on May 19, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    CLIIssues related to the Codex CLIbugSomething isn't workingconnectivityIssues involving networking or endpoint connectivity problems (disconnections)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions