TUI blocks all models when primary bucket hits 100%, even models that are not actually rate-limited

Open 💬 3 comments Opened May 17, 2026 by Gerry9000

Summary

When a long-running codex TUI session sees rate_limits.primary.used_percent reach 100% (regardless of which model triggered it), the session refuses to send further requests on any model — including models the server is not actually blocking, like gpt-5.3-codex-spark on a prolite plan.

A fresh codex session started in a new terminal works fine on the same model that the affected terminal refuses to use. The web portal correctly shows separate usage stats for spark vs. the main models, but the CLI's rate-limit envelope conflates them into a single limit_id: "codex" bucket.

Reproduction

  1. Start codex on gpt-5.5 (or whatever the default primary model is on a prolite plan)
  2. Burn through the 5-hour primary bucket until rate-limits return 100% on the primary window
  3. In a separate codex terminal already running gpt-5.3-codex-spark, attempt to send a message
  4. The spark terminal refuses to send, even though server-side spark is not blocked
  5. Open a brand-new terminal, launch codex, switch to gpt-5.3-codex-spark → works immediately on the same account

Expected Behavior

The TUI should use rate_limit_reached_type (the explicit server signal) to decide whether to block a request, not primary.used_percent alone. When rate_limit_reached_type: null, the server is permitting the request and the client should send it.

Alternatively, the rate-limit envelope should be enriched server-side to distinguish per-model availability the way the web portal does.

Evidence

I inspected a past spark session from a prolite account where rate_limits.primary.used_percent was 100% the entire time:

{
  "limit_id": "codex",
  "primary": {
    "used_percent": 100.0,
    "window_minutes": 300,
    "resets_at": ...
  },
  "secondary": { "used_percent": 62.0, "window_minutes": 10080, ... },
  "credits": { "has_credits": false, "balance": "0" },
  "plan_type": "prolite",
  "rate_limit_reached_type": null
}

That session logged 2275 successful response events at primary=100%. The server allows spark at 100% primary — the field rate_limit_reached_type: null confirms it.

Impact

Users hitting the primary bucket lose access to spark in any pre-existing terminal even though their spark allowance is unused. They must quit and restart codex to recover access. For long-running terminal sessions (tmux panes, persistent agents), this is a forced session loss with no workaround inside the running TUI.

Environment

  • codex-cli 0.130.0
  • Plan: prolite
  • Default model: gpt-5.5
  • Affected model when this happens: gpt-5.3-codex-spark

Suggested Fix

In the TUI's request gate, change the decision from:

if rate_limits.primary.used_percent >= 100: block_request()

to:

if rate_limits.rate_limit_reached_type is not None: block_request()

The used_percent: 100 value is informational (drives the UI meter), not authoritative for whether a specific request will be allowed. The authoritative signal is rate_limit_reached_type.

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗