[BUG] VS Code extension: dismissing the usage-limit banner does not hold — 'allowed' events clear dismissedRateLimitKey unconditionally

Status Open
Reported on v2.1.231
Maintainer reply None cached
Activity 0 comments · opened Aug 13, 2026

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:

  1. The allowed branch should only clear dismissedRateLimitKey when the allowed event is for the same rateLimitType as the dismissed key — an allowed for one bucket should not un-dismiss a warning about a different one.
  2. 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

  1. 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).
  2. Wait for the banner above the input box: You've used 57% of your weekly limit · resets in 4d.
  3. Click the × to dismiss it.
  4. Continue a normal session — send a prompt, let tool calls and any background/subagent requests run.
  5. 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.

View original on GitHub ↗