[BUG] "Approaching weekly usage limit" banner fires while the same panel shows the weekly window at 25%
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:
- There is no client-side projection or threshold math — no burn rate, no extrapolation.
surpassed_thresholdis a server-provided field. So "25% but approaching" cannot be explained as the client forecasting exhaustion. 5his tested before7d, so the weekly string cannot be a mislabelled 5-hour warning. Reaching that branch requires7d.status === "approaching_limit"and5h.status !== "approaching_limit"— even though 5h (68%) is by far the fuller window.- It cannot be a per-model weekly window bleeding through either:
7d_opus/7d_sonnet/7d_oiproduce 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, mapzg) keys on:5h,7d,7d_opus,7d_sonnet,7d_oi,7d_cowork,overage— i.e. per-model weekly windows. - Panel (
shared-11-Da5ltiie.js, functionrh) keys on:session,weekly_all, and per-product rows rendered asWeekly · {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'sapproaching_limitstatus — 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 bywindowName, 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
statuslegitimately reflects something other than the displayedutilization, 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.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗