[BUG] "Approaching weekly usage limit" banner fires while the same panel shows the weekly window at 25%

Status Open
Reported on v2.1.221
Maintainer reply None cached
Activity 1 comment · opened Aug 6, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet (nearest is #55835 → #50558, which is about dismissal persistence, not the trigger condition)
  • [x] This is a single bug report
  • [x] I am using the latest version

Environment

  • Claude desktop app 1.25927.0 (/Applications/Claude.app)
  • Bundled Claude Code CLI 2.1.221
  • macOS 26.5.2 (25F84)
  • Plan: Max (20x)

Summary

The "Approaching weekly usage limit" banner is displayed at the same moment the usage panel — directly adjacent, in the same window — shows Weekly · all models at 25%, six days from reset. The two readings contradict each other, and the banner is the one that looks wrong.

Observed simultaneously in a single screenshot:

| Surface | Reading |
|---|---|
| Banner | Approaching weekly usage limit · Resets Wed, Aug 12, 5:00 PM |
| Panel — 5-hour limit | 68%, resets in 1 hr 7 min |
| Panel — Weekly · all models | 25%, resets Wed 4:59 PM |
| Panel — Weekly · Fable | 0% |

The weekly window had rolled over ~18 hours earlier, so 25% consumed is plausible and self-consistent. Nothing on screen supports "approaching".

Why this looks like a real defect and not a projection

I checked the shipped bundle before filing, to rule out the obvious benign explanation (that the banner is a burn-rate projection rather than a level reading). It is not — the banner is a direct relay of a server-assigned status field.

In Contents/Resources/ion-dist/assets/v1/shared-8-Db0KUeRc.js, the window-selection function ends with:

const u = "approaching_limit"===e["5h"]?.status || "approaching_limit"===e["7d"]?.status;
if (o && !u) { /* per-model window: 7d_opus | 7d_sonnet | 7d_oi */ }
return "approaching_limit"===e["5h"]?.status ? { windowName:"5h",  ... }
     : "approaching_limit"===e["7d"]?.status ? { windowName:"7d",  ... }
     : "approaching_limit"===e.overage?.status ? { windowName:"overage", ... }
     : { windowName:null, ... };

and the copy is selected purely by windowName (c360a9e1c-DNZFFKN3.js):

: "5h"===m ? "Approaching session usage limit"
: "7d"===m ? "Approaching weekly usage limit"

Consequences worth noting:

  1. There is no client-side projection or threshold math — no burn rate, no extrapolation. surpassed_threshold is a server-provided field. So "25% but approaching" cannot be explained as the client forecasting exhaustion.
  2. 5h is tested before 7d, so the weekly string cannot be a mislabelled 5-hour warning. Reaching that branch requires 7d.status === "approaching_limit" and 5h.status !== "approaching_limit" — even though 5h (68%) is by far the fuller window.
  3. It cannot be a per-model weekly window bleeding through either: 7d_opus / 7d_sonnet / 7d_oi produce different, model-named copy.

So the client is faithfully rendering rate_limits["7d"].status = "approaching_limit" on a window whose own utilization is 25%. Either the server is assigning that status incorrectly, or status and utilization on the same 7d object are computed over different populations. Either way the user-visible pair is contradictory. (#55835 implies the weekly warning threshold sits near ~75%, which makes 25% harder to explain as intended.)

Secondary: the banner and the panel use different window taxonomies

This may deserve its own issue, but it is why a user cannot self-diagnose the above — the two surfaces are not describing the same set of things:

  • Banner (shared-8, map zg) keys on: 5h, 7d, 7d_opus, 7d_sonnet, 7d_oi, 7d_cowork, overage — i.e. per-model weekly windows.
  • Panel (shared-11-Da5ltiie.js, function rh) keys on: session, weekly_all, and per-product rows rendered as Weekly · {product}.

A banner can therefore name a window that has no corresponding row in the panel the user is looking at, and the panel can show rows (Weekly · Fable, above) that the banner logic has no concept of. There is no way to reconcile one against the other from the UI.

Two smaller instances of the same split:

  • The ring color threshold is a hardcoded client-side e >= 95 (Fg), independent of the server's approaching_limit status — so "the ring says fine, the banner says approaching" is reachable by construction.
  • In the exceeded path, when several windows are blown the tie-break picks the one with the latest resets_at (d.reduce((e,t)=>t.resetTime>e.resetTime?t:e)). That is defensible for "exceeded" (you are blocked until the last one clears), but since the banner text is chosen solely by windowName, a user with both 5h and 7d exhausted is told only about the weekly one.

Expected

Either:

  • the banner does not fire when the named window's own utilization is nowhere near its threshold; or
  • if status legitimately reflects something other than the displayed utilization, the banner says which limit and which number it means, so it can be reconciled with the panel shown beside it.

Impact

Low severity, but it is trust-eroding in a specific way: a warning that contradicts the number next to it teaches users to ignore the warning. For anyone scripting around usage (the rate_limits payload reaches a statusLine command), status and utilization disagreeing on the same object is a genuine correctness question about which field to key on.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗