CLI panics on malformed Retry-After in rate-limit error (Duration::from_secs_f64 overflow)

Open Beginner friendly
#26,770 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
2/5
Estimated time
1-3 hours
Newbie friendliness
72/100
Issue type
Bug
Clarity
Clearly specified
Activity status
Quiet
Tech stack
rust
Domain
api, cli

Research direction

Start in codex-rs/codex-api/src/sse/responses.rs at try_parse_retry_after and inspect the seconds branch around lines 509-533, along with the retry-after regex near line 574. Reproduce the oversized value from the issue in an isolated test and verify malformed or overflowing input returns no delay so the normal exponential backoff is used without a panic.

Written by the indexing model from the issue text.

Description

bug CLI rate-limits
What version of Codex CLI is running?

0.137.0

What subscription do you have?

N/A — source-review finding

Which model were you using?

N/A (platform-independent logic bug)

What platform is your computer?

N/A (platform-independent logic bug)

What terminal emulator and version are you using (if applicable)?

No response

Codex doctor report
not available
What issue are you seeing?

This is a source-review finding (not hit at runtime), reported defensively.

try_parse_retry_after in codex-rs/codex-api/src/sse/responses.rs:509-533 extracts a
number from the server-controlled error.message of a rate_limit_exceeded error
and passes it straight to Duration::from_secs_f64, which panics on overflow / non-finite
values:

let value = value.as_str().parse::<f64>().ok()?;   // no digit cap (regex L574)
return Some(Duration::from_secs_f64(value));         // panics on overflow

The regex at L574 — (\d+(?:\.\d+)?) — places no bound on the number of digits, and there
is no length limit on error.message and no clamp on the parsed value. A message such as
"… try again in 99999999999999999999s." (20 digits ≈ 1e20, exceeding u64::MAX seconds
≈ 1.8e19) parses to a finite f64 that overflows Duration, panicking the request task.
This sits directly on the SSE-decoding path, so a single malformed/adversarial upstream
response (e.g. a buggy or hostile custom/OSS provider or proxy) crashes the request.

What steps can reproduce the bug?

The overflow is provable in isolation (matches the exact call on L526):

let value: f64 = "99999999999999999999".parse().unwrap(); // ~1e20
let _ = std::time::Duration::from_secs_f64(value);          // panics: "overflow when ..."

End-to-end: have the model endpoint emit an SSE response.failed event with
error.code = "rate_limit_exceeded" and error.message containing
"try again in 99999999999999999999s". try_parse_retry_after then panics instead of
returning a delay.

What is the expected behavior?

A malformed/oversized Retry-After value should never panic; parsing should fail gracefully
and fall back to the normal exponential backoff (the same path as when no delay is parsed).

Additional information

Use the non-panicking constructor and/or clamp the value:

return Duration::try_from_secs_f64(value).ok();   // Rust 1.66+, returns None instead of panicking

Optionally clamp to a sane max (e.g. value.min(MAX_RETRY_AFTER_SECS)) before constructing
the Duration. The ms branch (L528) already uses a saturating as u64 cast and is safe;
only the seconds branch (L526) needs the fix.

Dominant language
Rust
Stars
125k
Forks
19.5k
Avg merge
1m
Merged PRs (30d)
1k

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from openai/codex

All issues in openai/codex

Similar issues

More Rust issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.