v2.1.119 incomplete fix: spurious rate-limit `<system-reminder>` still fires on release note body (not just PR titles)
What happened
Running gh release view v2.1.119 --repo anthropics/claude-code causes Claude Code to append a <system-reminder> block claiming "GitHub API rate limit exceeded" after the tool output, despite the actual rate limit being unexhausted.
Diagnosis
- Actual rate limit is fine.
gh api rate_limit --jq .resources.corereturned{"limit":5000,"remaining":5000,"used":0}at the time the warning fired. - Upstream release body does NOT contain the reminder. Fetching the raw JSON via
gh api repos/anthropics/claude-code/releases/tags/v2.1.119 --jq .bodyyields a body that ends cleanly with- [VSCode] Fixed voice dictation's first recording producing nothing...\n— no<system-reminder>tag. - The release body contains the literal string "rate limit" because one of its own entries is the v2.1.119 fix note: "Fixed spurious 'GitHub API rate limit exceeded' hints when
ghoutput contained PR titles mentioning 'rate limit'".
It appears the v2.1.119 fix narrowed the heuristic so it no longer fires on PR-title matches, but the same heuristic still fires when the substring rate limit appears elsewhere in gh stdout — e.g. release note bodies — and the injected block is the full multi-sentence <system-reminder> shown below.
The injected reminder (verbatim)
<system-reminder>GitHub API rate limit exceeded (5,000/hr shared across all tools and agents). Run `gh api rate_limit --jq .resources` and sleep until reset before further gh calls. If polling in a loop, use ScheduleWakeup instead of retrying.</system-reminder>
Why it matters
The injected block is syntactically indistinguishable from legitimate Claude Code internal reminders. In sessions where the assistant does not cross-check the actual rate_limit API before acting on the text, this will cause:
- spurious stop/defer decisions,
- redundant
gh api rate_limitcalls, - unnecessary
ScheduleWakeupschedules.
More broadly, it weakens the injection-defense posture: if the harness itself injects <system-reminder> blocks derived from untrusted tool output (even with good intent), it normalizes the pattern that the safety spec explicitly treats as untrusted.
Reproduction
$ claude --version
2.1.119 (Claude Code)
$ gh api rate_limit --jq .resources.core
{"limit":5000,"remaining":5000,"reset":...,"used":0}
$ gh release view v2.1.119 --repo anthropics/claude-code
...<full release body>...
<system-reminder>GitHub API rate limit exceeded ...</system-reminder>
Confirmed 100% reproducible on:
- macOS Darwin 25.5.0, arm64
- Claude Code 2.1.119
- gh 2.x
Suggested fix
The heuristic that produces these rate-limit reminders should not rely on substring scans of gh stdout bodies. GitHub already returns authoritative rate state in response headers (x-ratelimit-*) for every API call. Gating the reminder on those headers — or on an actual threshold breach from a side rate_limit probe — would remove the class of false positives entirely.
Minimum change: suppress the heuristic when the gh subcommand is a pure read (release view, repo view, api) and the body is being treated as text-for-display rather than as a response to a mutating call.
---
This issue was drafted and filed by Claude Code (Opus 4.7, 1M context) while assisting a user who noticed the false-positive live during a gh release view v2.1.119 call. The filing account is the human user; the investigation (rate-limit verification, raw-body comparison, issue-tracker search for duplicates) was performed by Claude.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗