Rate limit errors show 'API Error' without distinguishing usage vs throughput limits
Problem
Users on paid plans (including Pro Max $200/month) are encountering API Error: Rate limit reached messages when their usage dashboard shows they haven't hit their limits. This creates confusion and disrupts workflow because the error message doesn't clarify what limit was reached.
Current Behavior
- User at 32% session usage, 98% weekly usage sends a message
- Claude Code returns:
⎿ API Error: Rate limit reached - Usage dashboard shows limits not at 100%
- User is confused - what limit? Why now?
Root Cause
There are two types of rate limits, but only one is visible:
| Limit Type | Visible in Dashboard? | What it controls |
|------------|----------------------|------------------|
| Usage limits (weekly/session) | ✅ Yes | Total tokens/requests allowed |
| Throughput limits (requests/min) | ❌ No | How fast you can make requests |
The error message conflates these. Users hit the burst/throughput limit (requests per minute cap) but the message makes it sound like they've exhausted their usage quota.
Impact
- Flow disruption: Users stop working, thinking they're out of quota
- Support burden: Users file complaints about "hitting limits at 32%"
- Plan confusion: "I'm paying $200/month, why am I throttled?"
- No actionable guidance: Message doesn't explain the fix (wait 60s vs stop for the week)
Proposed Solutions
Option 1: Distinguish error messages
Current: API Error: Rate limit reached
Better: Rate limit: Too many requests per minute. Retry in 60s.
vs
Better: Usage limit: Weekly quota exhausted. Resets Sun 5:59 PM.
Option 2: Show throughput limits in dashboard
Add a "Requests/min" meter to the Usage page so users can see both types of limits.
Option 3: Auto-retry with backoff
When Claude Code hits throughput limits, automatically retry after 60s instead of surfacing the error.
Reproduction
- Send several messages in quick succession on Opus (tool-heavy tasks)
- Observe
API Error: Rate limit reacheddespite dashboard showing <100% usage - Wait 60 seconds, retry → works fine
Environment
- Plan: Pro Max ($200/month)
- Model: Opus 4.6
- Usage at time of error: 32% session, 98% weekly
- Platform: macOS, Claude Code CLI v2.1.42
User Quote
"I pay $200 pro max 20% extra plan. Now this is not fair. It's really bugging my workflow. I understand if I reached usage 100% yes you hit a usage limit but I'm not using any API keys here why I'm receiving this API error rate limit reached that needs to be fixed."
Expected Outcome
Error messages should be specific and actionable:
- Tell users which limit they hit (usage vs throughput)
- Provide clear next steps (wait vs upgrade vs use Sonnet)
- Show all relevant limits in the dashboard
31 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
I went through "Rate limit errors show 'API Error' without distinguishing usage vs throughput limits" plus the discussion thread and mapped the failing path.
Problem I see: Users on paid plans (including Pro Max $200/month) are encountering API Error: Rate limit reached messages when their usage dashboard shows they haven't hit their limits. This creates confusion and disrupts workflow because the error message doesn't clarify what limit was reached.
Root-cause hypothesis: an auth/session state mismatch across validation steps.
First patch plan: reproduce the flow with deterministic steps, inspect auth/session state transitions, patch validation around the wrong-code path, and add regression coverage for happy and failure flows.
If you want this path, I can share deterministic repro notes up front and then submit the minimal fix.
I am also hitting "API Error: Rate limit reached" and my usage dashboard is way below limits.
I AM HAVING THIS ISSUE ON VSCODE EVEN THOUGH I USE MY OAUTH CONNECTION
This looks less like a “mystery limit” and more like a taxonomy gap.
There are at least two distinct limiters here:
Both currently surface as “API Error: Rate limit reached,” which makes it impossible for users to take the correct next step.
To make this actionable, a tiny redacted log from 1–3 failures would help clarify which limiter is firing. No prompts/content needed — just:
retry-afterorx-ratelimit-*headers (if present)If it’s throughput, the fix path is clear:
If it’s usage exhaustion, the UX should clearly say so.
Happy to help distill this into a minimal repro/runbook if useful.
Getting this issue as well - but only if I choose a model which has 1 mil context window like opus 4.6.
Also for me it doesn't matter if I use vscode claude code extension or iPhone Claude native app - getting the same error anyways ; and my usage is way below limits. My claude subscription is Max plan.
This confusion between throughput limits and usage quota limits is one of the most frustrating parts of the Claude API experience. The error message is identical for two completely different situations that require completely different responses — wait 60 seconds vs. stop for the week.
The underlying data to distinguish these actually exists in the API response headers (anthropic-ratelimit-requests-remaining, anthropic-ratelimit-tokens-remaining, etc.), but Claude Code doesn't surface it clearly when things go wrong.
I built an open-source proxy called ClaudeTrack that reads these rate limit headers from every API response and gives you real-time visibility into exactly where you stand — requests remaining, tokens remaining, and which one you're closer to exhausting.
It also predicts when you're likely to hit a limit based on your consumption pattern, so you get a warning at 75% and 90% before you see the error. You can see the live status on the dashboard, no more guessing.
It's self-hosted, MIT licensed, and takes about 2 minutes to set up with Docker. Doesn't solve the Claude Code CLI error message itself, but it gives you a separate source of truth for your rate limit status.
+1 — ClaudeTrack looks like a solid “surface the headers” workaround. That’s also the point: the data to disambiguate quota vs throughput already exists, but Claude Code collapses it into one message.
If someone can paste one redacted failure (HTTP status + retry-after and anthropic-ratelimit-* headers, plus whether it was streaming), I can classify which limiter is firing and propose a minimal CLI patch that prints: (a) limiter type, (b) “wait Xs” vs “stop until reset,” and (c) the relevant remaining counters.
Happy to open a PR if maintainers are open to it.
+1, I contacted support through different channels and they all replied with the same generic description of the pricing, which makes the whole situation much more frustrating.
I already pay the 100€/month subscription and blocked me after 10 minutes of use when I have barely used it in the last 7 days. This is not normal.
This is the first time I use Claude since my previous message.
What is going on?
<img width="587" height="166" alt="Image" src="https://github.com/user-attachments/assets/f3a7d707-05b5-4d50-a27f-509db1c1186e" />
same ... Claude Max 5 and get Rate limits - subscriptions between ios seems also a problem ...
Another week and the issue remains.
Worth mentioning it only happens when using Opus
<img width="511" height="332" alt="Image" src="https://github.com/user-attachments/assets/bbc5af85-39f7-4647-9523-be8d05ba3e83" />
I had to recreate a new session — the old one can no longer be used. But here is the truth: Claude loses all style and depth from previous sessions unless you build a robust memory and structured documentation from Claude itself. This is simply annoying, as you have to re-teach Claude again at the cost of token credits. I don't know whether this is intentional — to drain users' capacity consumption — or simply a misconception on the user's side.
<img width="678" height="577" alt="Image" src="https://github.com/user-attachments/assets/b81defbb-4816-4364-a8d0-7abfad90622d" />
its totally annyoing
The header data @smarth-tech mentioned (anthropic-ratelimit-requests-remaining,
anthropic-ratelimit-tokens-remaining) is exactly what's needed to make
this actionable at the CLI level.
ClaudeTrack reading those headers is the right layer — if the classifier
knew which bucket fired, the CLI copy writes itself:
For anyone hitting this: if you can capture the full response headers
from a failure, paste them here and I can classify which limiter fired
and what the correct next step is. The data is already there — it's
just not being surfaced.
— tracking these patterns at github.com/SirBrenton/pitstop-truth
<img width="843" height="924" alt="Image" src="https://github.com/user-attachments/assets/6adfd2df-95f2-4ecd-9822-03729c8351db" />
<img width="2190" height="483" alt="Image" src="https://github.com/user-attachments/assets/30666775-fa69-4ae6-a027-2b3a33dd0b9f" />
I received the API rate limit reached message, I went to bed, and in the next day, even though the usage limits are apparently clear I can't do anything and the error messages persists.
@filipe-pieruccetti, those screenshots are useful. Session at 0% and weekly at 11% rules out quota exhaustion, which means something else is firing — likely a throughput or context-tier limit that doesn't show in the dashboard.
If you can capture the response headers from one of those failures (the
anthropic-ratelimit-*headers and anyretry-aftervalue), I can tell you exactly which limiter fired and whether waiting will actually help.Captured the headers. The culprit is anthropic-ratelimit-unified-overage-status: rejected with overage-disabled-reason: org_level_disabled. This means when the 5h window fills, there's no fallback — it hard-blocks instead. The error message says "rate limit reached" with no indication it's a 5-hour rolling window or that waiting ~a few hours will fix it. Dashboard doesn't expose the 5h window utilization either, only session/weekly.
@filipe-pieruccetti, that header is the signal.
anthropic-ratelimit-unified-overage-status: rejectedwithoverage-disabled-reason: org_level_disabledpoints to a different limiter than the usual throughput throttle.This is a rolling-window exhaustion case (looks like a ~5h window) with no overage fallback allowed, so it hard-blocks until the window resets — regardless of what the session/weekly dashboard shows.
That’s why this feels confusing: it surfaces as the same “rate limit reached” message, but the correct action here isn’t short backoff — it’s effectively wait for the window to clear.
So there are at least three distinct cases getting collapsed into one message right now:
wait for window reset (~4h)
The error doesn't tell you which one you hit, so people apply the wrong fix.
If you can share the full header block redacted, I can turn this into a clean classification note — this is exactly the primary evidence that's missing from the current error story.
"These headers were captured after the window reset (successful request). During the block, the dashboard showed 0% session and 11% weekly. The overage-disabled flag was present in the success headers too — I didn't capture the failure headers directly, but this confirms the limiter type."
"anthropic-ratelimit-unified-status": "allowed",
"anthropic-ratelimit-unified-5h-status": "allowed",
"anthropic-ratelimit-unified-5h-reset": "1774908000",
"anthropic-ratelimit-unified-5h-utilization": "0.35",
"anthropic-ratelimit-unified-7d-status": "allowed",
"anthropic-ratelimit-unified-7d-reset": "1775440800",
"anthropic-ratelimit-unified-7d-utilization": "0.13",
"anthropic-ratelimit-unified-representative-claim": "five_hour",
"anthropic-ratelimit-unified-fallback-percentage": "0.5",
"anthropic-ratelimit-unified-reset": "1774908000",
"anthropic-ratelimit-unified-overage-status": "rejected",
"anthropic-ratelimit-unified-overage-disabled-reason": "org_level_disabled"
when unified-5h-utilization was at or near 1.0 and unified-status was "blocked" instead of "allowed". That's the smoking gun header block that shows all three fields together: window full + overage rejected + hard block.
<img width="711" height="746" alt="Image" src="https://github.com/user-attachments/assets/362c792c-5982-4c29-afd3-a6f8ee1ddc6c" />
this is a bummer ! paying additional credits and still get cut off
<img width="1357" height="121" alt="Image" src="https://github.com/user-attachments/assets/bf62d7d3-4e82-40d7-bba1-9ac9f90e1038" />
and after a few minutes doing nothing this went to the top
<img width="702" height="232" alt="Image" src="https://github.com/user-attachments/assets/9b9a753a-7ad9-446d-a7b8-ce211dbcd2ac" />
WOW ! this is unacceptable
体験:6分50秒の無応答ハング、原因特定手段なし
環境:
発生した事象
原因切り分けの試行(すべて不発)
/cost→ "You are currently using your subscription to power your claude code usage" と表示されるのみ。サブスクリプション利用者にはトークン/レート情報が提供されない。/status→ 5時間リミット:34%used、Weeklyリミット:62%used。/status上は両方のリミットに余裕があり、ハングの原因を特定する手段がなかった。調査の結果、毎分スループット制限(RPM/ITPM/OTPM)に到達したと推定されるが、これは/statusに一切表示されない。問題の構造
レート制限には少なくとも3つの独立したレイヤーがある:
/statusで表示される/statusで表示されるレイヤー3に到達した場合でも、CLIは無言でハングするだけで:
/statusは「問題なし」と表示し続けるユーザーへの切り分けコスト転嫁
現状、ユーザーは以下を自力で行う必要がある:
~/.claude/内のJSONLファイルを手動パースしてトークン消費量を推定これはデバッグ作業であり、$20/月であっても$200/月であっても、有料ユーザーに求めるべき作業ではない、と考える
提案
/statusに RPM/ITPM/OTPM の現在値と上限を表示するThroughput limit: ITPM exceeded. Retry in 45s.(使用量制限とは明確に区別)@bibourokushi — this is a precise breakdown of exactly the problem. The three-layer structure you've identified (5h window, weekly cap, per-minute throughput) is the same pattern documented across multiple systems.
The silent hang is the worst case — no signal means no correct action. At minimum the CLI should surface which layer fired and whether waiting will help.
If you can capture the response headers from one of those failures, I can classify exactly which limiter fired and what the correct wait time is.
— tracking these patterns at
github.com/SirBrenton/pitstop-truth
I can take anthropics/claude-code#25805.
For "Rate limit errors show 'API Error' without distinguishing usage vs throughput limits", I will start by reproducing the UI/layout issue and isolating the component/state that causes it.
Target: draft PR in ~8h.
Deliverables: minimal UI fix aligned with current UX; quick before/after validation notes; PR with clear change summary.
I keep UI changes consistent and low-risk, with quick validation notes. (@Asobu01)
Quick follow-up on
anthropics/claude-code#25805. I am still ready to start immediately and can post the first repro/checklist note before the draft PR if helpful. If you want me on this one, I can begin now. (@Asobu01)The 429 response carries
anthropic-ratelimit-*headers that signal which bucket fired (requests-per-min vs tokens-per-min) plus aretry-afterwhen present. Surfacing whichever header is at zero, with the retry-after, in the CLI message would give users a concrete next step without any API change. Right now both signals get dropped before they reach the terminal.This issue has shown up in three forms so far.
1) Throughput vs quota confusion. Same error, different causes.
2) Rolling window overage. Needed a long wait, treated like a short retry.
3) Current state:
Retry-After is present.
Auth buckets are scoped.
CLI parses headers.
Install still fails.
So the problem is no longer missing signals. The signals are there, but they are not driving a decision in the CLI.
Reference:
https://github.com/SirBrenton/pitstop-truth/blob/main/receipts/2026/05/PT-2026-05-05-github-anthropics-claude-code-25805-429-signal-not-actionable/receipt.json
OP's split is right but there's a third axis: server quota (the object claude.ai/settings/usage renders, weekly + 5h rolling counters), throughput cap (RPM, not exposed anywhere), and local token tallies (what ccusage parses out of ~/.claude/projects/.jsonl). Local tallies can't see the server quota at all, and the server endpoint doesn't expose RPM. So 32% session + 98% weekly + RPM-throttled all collapse into the same 'Rate limit reached' string. Surfacing the X-RateLimit- headers on the rejected response would fix most of this without touching the dashboard at all.
Wrote up the three-receipt arc for anyone following this thread:
https://blog.pitstop.dev/i-tracked-this-bug-across-three-months-the-signals-were-there-the-whole-time/
Three months, three distinct failure shapes, one issue.
Closing for now — inactive for too long. Please open a new issue if this is still relevant.