Usage panel shows "1% left" while backend-api/codex/usage reports 81% used (19% left); requests still succeed

Open 💬 1 comment Opened Aug 7, 2026 by sami-lee

What version of the Codex App are you using (From “About Codex” dialog)?

26.730.61639 (build 6234)

What subscription do you have?

Pro ($100/mo) — API reports plan_type: "prolite"

What platform is your computer?

macOS 26.5.1 (build 25F80) — uname -mprs: Darwin 25.5.0 arm64 arm

What issue are you seeing?

The Usage & billing panel shows:

Weekly usage limit — Resets 13:37 — 1% left

and a banner reading:

1% usage remaining — Resets every week · Next reset is at 13:37 [Add credits] [Upgrade]

The backend disagrees. GET https://chatgpt.com/backend-api/codex/usage, called
from the same machine with the credentials in ~/.codex/auth.json, returns
81% used (19% remaining) with limit_reached: false, resetting
Wed 12 Aug 2026 22:16 AEST — 117.6 hours away, not today.

Every other field in the same panel matches that API response exactly, so the
app is authenticating to the right account and reading the right endpoint. Only
the General → Weekly row renders incorrectly:

| Panel field | API response | Match |
| --- | --- | --- |
| Credits balance US$0 | credits.balance: "0" | yes |
| Usage limit resets: "No resets available" | rate_limit_reset_credits.available_count: 0 | yes |
| GPT-5.3-Codex-Spark: "100% left, Resets 15 Aug" | used_percent: 0, reset_at → Sat 15/08 | yes |
| Weekly usage limit: "1% left, Resets 13:37" | used_percent: 81, reset_at → Wed 12/08 22:16 | NO |

API response (identifiers redacted):

{
  "plan_type": "prolite",
  "rate_limit": {
    "allowed": true,
    "limit_reached": false,
    "primary_window": {
      "used_percent": 81,
      "limit_window_seconds": 604800,
      "reset_after_seconds": 423581,
      "reset_at": 1786536977
    },
    "secondary_window": null
  },
  "additional_rate_limits": [
    {
      "limit_name": "GPT-5.3-Codex-Spark",
      "metered_feature": "codex_bengalfox",
      "rate_limit": { "primary_window": { "used_percent": 0, "reset_at": 1786718196 } }
    }
  ],
  "credits": { "has_credits": false, "balance": "0" },
  "rate_limit_reset_credits": { "available_count": 0 }
}

There appear to be two defects in the one row:

  1. Percentage. 81% used should render "19% left". It renders "1% left",

consistent with a dropped leading digit rather than an unrelated value.

  1. Reset time. The row shows a bare "13:37", implying a reset within the

day. reset_at: 1786536977 is Wed 12 Aug 22:16 local (12:16 UTC). No offset
yields 13:37, and the Spark row in the same panel renders its reset date
correctly.

What steps can reproduce the bug?

  1. On a prolite plan, consume part of the weekly window.
  2. Open Usage & billing in the desktop app and read General → Weekly usage limit.
  3. Call GET https://chatgpt.com/backend-api/codex/usage with

Authorization: Bearer <tokens.access_token> and
ChatGPT-Account-Id: <tokens.account_id> from ~/.codex/auth.json.

  1. Compare. The panel reported 1% left; the API reported 81% used.

Confirmed by sending a request while the panel claimed 1% and showed the
"Add credits / Upgrade" banner.
A one-word prompt was sent through the same
app. It was served normally, and the token_count event Codex wrote for that
turn carried:

"rate_limits": {
  "primary": { "used_percent": 81.0, "window_minutes": 10080 },
  "rate_limit_reached_type": null
}
  • Session id: 019fdcad-bc06-7db3-b278-979cd1e94dc3
  • Token usage for that turn: 25,311 total (25,301 input / 11,008 cached / 10 output)
  • Context window: 258,400
  • Rate limit usage reported by the server on that same turn: 81%

So the client received used_percent: 81 from the server on the very request
the panel claimed there was no allowance for. The wrong value is introduced in
the display layer, not the API.

A second OpenAI client on the same machine and account renders it
correctly.
The Codex VS Code extension's "Usage remaining" panel shows:

Weekly — 19% — 12 Aug

which matches backend-api/codex/usage exactly. So at the same moment, signed
into the same account against the same backend:

| Client | Weekly remaining | Reset |
| --- | --- | --- |
| backend-api/codex/usage | 19% | Wed 12 Aug 22:16 |
| Codex VS Code extension | 19% | 12 Aug |
| Codex desktop app | 1% | 13:37 |

This rules out an account-, plan- or backend-side cause and localises the defect
to the desktop app's usage display.

Persists across a full quit and relaunch of the app, so it is not a transient
cache.

What is the expected behavior?

The Weekly usage limit row should match the backend: 19% left, resetting
Wed 12 Aug 22:16 local
, and no "out of allowance" banner should be shown while
limit_reached is false.

Additional information

This is not the first time. On previous occasions the same panel has reported a
near-zero remaining figure and the assumption was that the allowance really was
exhausted, so work stopped for the rest of the cycle. Only checking the API
directly this time revealed the panel was wrong.

That is the practical impact: the error runs in the direction that costs the
user. A wrongly low figure paired with an "Add credits / Upgrade" banner leads
people either to stop working for days of allowance they actually have, or to
buy credits they do not need. Because the panel is the only surface most users
see, there is nothing to contradict it.

View original on GitHub ↗

1 Comment

tylerchen0123-sudo · 16 days ago

One implementation detail that may help isolate this display path: I would treat token_count.rate_limits as an independent latest-state stream, not as a field that only refreshes when token usage advances. A rate-limit snapshot can be newer even when the cumulative token counter is unchanged, so coupling the panel refresh to “new usage row accepted” can leave quota state stale or mismatched.

In a small local Codex monitor I keep the newest rate_limits payload by event timestamp separately from fresh/cache/output accounting: https://github.com/tylerchen0123-sudo/CODEX-Inspection-Guidelines-for-Dosage/blob/main/collector.py

For the desktop row I’d key/render from the newest (limit_id, window_minutes, used_percent, resets_at) tuple and derive “left” only at presentation time as 100 - used_percent; missing/unknown values should stay unknown rather than fall through to an old row. A focused regression fixture with unchanged cumulative token usage but a newer rate_limits snapshot would catch accidental coupling between usage accounting and quota display.