codex - 💡(How to fix) Fix codex-client/retry: TransportError::RetryLimit is unreachable — retry exhaustion surfaces wrong error [1 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openai/codex#23404Fetched 2026-05-20 03:50:40
View on GitHub
Comments
0
Participants
1
Timeline
4
Reactions
0
Participants
Timeline (top)
labeled ×3cross-referenced ×1

Error Message

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. 3. The Err(err) => return Err(err) branch fires, returning the raw error After exhausting all retries, run_with_retry should return Err(TransportError::RetryLimit). This would then be correctly converted by api_bridge.rs into CodexErr::RetryLimitResponseTooManyFailedAttempts, giving users a clear, actionable error message instead of a raw 5xx or network error. 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.

Code Example

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

// After  
for attempt in 0..policy.max_attempts {
RAW_BUFFERClick to expand / collapse

What issue are you seeing?

TransportError::RetryLimit is defined and matched throughout the codebase (in api_bridge.rs it becomes CodexErr::RetryLimitResponseTooManyFailedAttempts), 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::RetryLimitResponseTooManyFailedAttempts, 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.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

codex - 💡(How to fix) Fix codex-client/retry: TransportError::RetryLimit is unreachable — retry exhaustion surfaces wrong error [1 participants]