[BUG] VS Code extension: dismissing the usage-limit banner does not hold — 'allowed' events clear dismissedRateLimitKey unconditionally
Preflight Checklist
- [x] I have searched existing issues — the dismissal defect described here has not been reported. Related but distinct issues are listed under "Additional Information" below.
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
What's Wrong?
Dismissing the usage-limit banner in the VS Code extension does not work. Clicking the × makes the banner disappear, and it returns within seconds — same session, no reload, no change in my usage level.
This is a defect in the dismiss control itself, not a request to change when the banner appears or to add a setting to hide it.
Root cause. In the webview bundle (webview/index.js, extension 2.1.231), the rate_limit_event handler is:
else if (e.type === "rate_limit_event") {
let i = e.rate_limit_info, n = `${i.status}:${i.rateLimitType ?? ""}`;
this.currentRateLimitKey = n;
if (i.status === "allowed") { this.rateLimitWarning.value = null; this.dismissedRateLimitKey = null }
else if (n !== this.dismissedRateLimitKey) this.rateLimitWarning.value = Klt(i)
and dismissal is:
dismissRateLimitWarning() {
if (this.rateLimitWarning.value) this.dismissedRateLimitKey = this.currentRateLimitKey, this.rateLimitWarning.value = null
}
Dismissal records the key "${status}:${rateLimitType}", but the status === "allowed" branch clears dismissedRateLimitKey unconditionally, regardless of which rateLimitType that allowed event refers to.
A rate_limit_event is emitted per API response, and status falls back to "allowed" whenever that response's headers carry no anthropic-ratelimit-unified-*-surpassed-threshold marker — in the CLI bundle, uSp() returns null and the caller sets S = "allowed". That marker is not on every response, and background calls, subagents and other buckets each generate their own events. So a dismissed allowed_warning:seven_day is un-dismissed by the very next unmarked response, and the next marked response re-renders the banner. Hence "gone for a few seconds, then back."
Secondarily, dismissedRateLimitKey is a plain instance field rather than persisted state, so a webview reload also discards it.
What Should Happen?
Clicking × should keep the banner hidden for that limit state. Specifically:
- The
allowedbranch should only cleardismissedRateLimitKeywhen theallowedevent is for the samerateLimitTypeas the dismissed key — anallowedfor one bucket should not un-dismiss a warning about a different one. - The dismissal should survive a webview reload (persisted rather than held in an instance field).
Escalation should still re-show it — going from allowed_warning to rejected, or a genuinely different limit type, already produces a different key and would surface a new banner, which is the correct behaviour.
Steps to Reproduce
- Use the VS Code extension on an account whose weekly usage is high enough that the server sets a surpassed-threshold header (mine appeared at 57% weekly utilization with 4 days left in the window).
- Wait for the banner above the input box:
You've used 57% of your weekly limit · resets in 4d. - Click the × to dismiss it.
- Continue a normal session — send a prompt, let tool calls and any background/subagent requests run.
- The banner reappears within seconds, unchanged, in the same session.
The interval varies with how quickly a response arrives lacking the threshold header followed by one carrying it, so it can be near-immediate or take a few turns.
Claude Code Version
2.1.198 (Claude Code); VS Code extension anthropic.claude-code-2.1.231-darwin-arm64
Is this a regression?
I don't know
Platform
Anthropic API
Operating System
macOS (15.5, arm64)
Terminal/Shell
VS Code extension (native), zsh
Additional Information
Related but distinct — all of these ask for a configurable threshold or an opt-out setting, which is a feature request; this report is that the existing dismiss control does not function as designed:
- #72994 (open) — configurable threshold or opt-out. I have commented there with the same root-cause analysis, since it makes their "dismiss once per window" option cheaper to implement.
- #41822, #28136 — both closed NOT_PLANNED
- #50558, #55572 — both auto-closed as duplicates
One data point on the trigger, for context only: the client's own burn-rate table for seven_day is [{utilization: 0.75, timePct: 0.6}, {0.5, 0.35}, {0.25, 0.15}], matched as utilization >= U && elapsedFraction <= timePct. At 57% used with 4d left of a 7d window (elapsedFraction ≈ 0.43) none of those match, so the banner I dismissed came from the server-side -7d-surpassed-threshold header rather than the local table. Not what this bug is about, but it explains why the banner was on screen to be dismissed in the first place.