[BUG] Contradictory 'session limit resets at X' times across one session; background subagents die terminally and reset projections silently roll forward
Status Open
Maintainer reply None cached
Activity 9 comments · opened Jul 3, 2026
Environment
Claude Code CLI on macOS (darwin 24.6.0), subscription auth (not Bedrock), model claude-fable-5, heavy use of background subagents via the Workflow/Agent tools.
What happened (timeline, one session, 2026-07-03, America/Los_Angeles)
- ~06:08 PT: a background workflow subagent failed terminally with: "You've hit your session limit - resets 8am (America/Los_Angeles)".
- 06:08-11:38 PT: the MAIN session loop kept working fine the whole time (deploys, tool calls), and two more multi-agent workflows ran to completion (~3.3M subagent tokens). Only individual subagents were dying.
- 11:38 PT: another background subagent failed terminally with: "You've hit your session limit - resets 2:10pm (America/Los_Angeles)".
- After 2:10pm PT the user was STILL blocked, now with errors projecting a reset around 7pm PT (2:10pm + 5h -- exactly one rolling-window length later, consistent with freshly-resumed consumption re-pinning the projection).
- The user purchased usage credits, which unblocked everything immediately.
Why this is a bug (or at least three UX defects)
- The reset time reads as a promise but is a snapshot. Each error message states an absolute clock time, but the 5-hour rolling window means any consumption after the snapshot silently moves the real reset later. A user who waits until the stated time and finds a LATER time in the next error reasonably concludes state corruption (this user's exact question: "Is there an auth token corruption?"). The message should either say the window is rolling ("earliest possible resume, moves with continued usage") or the client should show live window state.
- Background subagents share the pool invisibly and die terminally. The main loop and its background workflow agents draw from one subscription window, but there is no attribution in the error: the user cannot see that their own session's background fan-out is what consumed the window and keeps pushing the reset forward. Subagents that hit the limit die with a terminal failure rather than pausing/queueing until the window frees; after the user purchases credits, dead subagents do not resume -- the orchestrating session has to detect the death and respawn manually.
- Inconsistent enforcement within one session. For hours, the main loop succeeded while spawned subagents were rejected with session-limit errors. If the limit applies per pool, the main loop should have been throttled too; if subagents have a separate/earlier cutoff, the error message should say so. The mixed behavior amplifies the corruption impression.
Expected
- Rate-limit errors state that the window is rolling and the projection is a lower bound, or the CLI surfaces live usage-window state (e.g. in /usage).
- Subagent limit-failures are queued/retried when the window frees or credits are added, rather than requiring manual respawn.
- Reset projections that account for the session's own in-flight background consumption.
Related
#56570 (closed) reported the reset-not-triggering symptom; this report adds the rolling-window snapshot semantics + background-subagent attribution + terminal-subagent-death angle, reproduced across multiple errors in a single session.
9 Comments
Material update from the affected user that changes the likely diagnosis: the client's /status view showed the subscription quota NOT exhausted at the same time the background subagents were failing with 'You've hit your session limit - resets at X'.
Combined with the other observations, the evidence now points away from rolling-window semantics and toward a POOL MISMATCH with misattributed error text:
Net effect on the user: a misleading error cost real money -- they purchased $100 in extra-usage credits to route around a 'session limit' that the client's own /status said they had not hit.
Requests, updated:
One more cost dimension from the same incident, per the affected user: DOUBLE BILLING FOR ORPHANED WORK. When the mislabeled limiter kills a background subagent terminally, the tokens that agent consumed before dying are still charged -- but the work is orphaned (our first implementation agent died at spawn after its full prompt+context was consumed; a synthesis agent died AFTER its 12 upstream finder agents had burned ~2.4M tokens, requiring manual re-synthesis). The user then purchased extra-usage credits to unblock -- paying a second time to redo/resume work the first charge already covered. When a limiter rejects an agent, either the partial consumption should not bill, or the agent should suspend-and-resume when capacity returns, so a limiter mislabel does not convert directly into double spend.
ESCALATION -- the failure reproduced ON PAID CREDITS, and there is now concrete evidence pointing at the mechanism.
New incident (2026-07-03, ~14:35 PT): after the user purchased $100 of extra-usage credits, the next background subagent ran for 16.4 minutes (61 tool calls) and was then killed with '[implement:n1] failed: You've hit your session limit - resets 7pm (America/Los_Angeles)'. Workflow usage block, verbatim: agents_done 0, agents_error 1, subagent_tokens 374904, duration_ms 982109. Those 374,904 tokens were billed against the just-purchased credits and produced zero recoverable output (read-only recon; no disk artifacts). The user then purchased another $50 -- total $150 spent routing around this -- while the client's /status continued to show the subscription under quota.
Mechanism evidence -- the harness's auxiliary model dependency:
Coherent hypothesis: the subagent pipeline has a hard dependency on claude-opus-4-8[1m] (at minimum the safety classifier, possibly subagent supervision), and it is THAT model's limiter/availability that kills subagents -- while the 'session limit' error text and the /status display both refer to the session model's window, which was never exhausted. Users are shown a limit they have not hit, wait for resets that change nothing, and buy credits that do not map to the failing dependency -- and the killed agents' consumption bills anyway.
Requested remediation, updated:
Adding a user-side angle that may stop the bleeding for anyone else who lands here, plus a way to confirm the pool mismatch before spending more — because the costly part of this is buying credits that don't map to the limiter that's actually rejecting you.
The tell you already surfaced is the load-bearing one. In the same session, verbatim:
claude-opus-4-8[1m] is temporarily unavailable, so auto mode cannot determine the safety of Bash right nowNote: claude-opus-4-8[1m] (the safety classifier) was unavailable when reviewing this subagent's workThat points at an auxiliary-model dependency in the subagent path that is separate from your session model (
claude-fable-5) and separate from the window/statusrenders. If that auxiliary model's capacity is what's rejecting spawns, then neither waiting for the session-window reset nor buying extra-usage credits maps to it — which is exactly what you saw (waits changed nothing; even a credit-funded agent died at 374,904 tokens).A confirmation check you can run before buying anything. Scan the current session for the co-occurrence of (a) the auxiliary-model-unavailable string and (b) a subagent killed with
hit your session limit, while/statusshows headroom. If all three hold, the rejection is very likely auxiliary-model capacity — not your subscription window and not credits — so don't buy credits yet. Small stdin filter, tested against your verbatim strings:On your incident's four lines it returns:
On a plain
hit your session limitdeath with no auxiliary-model signal it returnskilled_but_no_aux_signal__check_/status_firstinstead, so it distinguishes the two cases rather than crying wolf on every limit message.Honest limits: this is visibility only — not prevention, not a refund. It can't stop the auxiliary-model dependency from killing subagents, it can't un-bill the orphaned tokens, and it leans on those exact strings staying stable across versions. Every real fix is on Anthropic's side. I'd narrow the asks to the two that are cheap for them and actually end the double-spend:
/status. "You've hit your session limit" has to say which pool rejected the request (subscription window / extra-usage credits / auxiliary-model capacity / org). A generic message pointing at a window/statusshows as healthy is what turned a display bug into $150 of spend.Your rolling-vs-snapshot ask still stands, but #1 alone would have stopped the spend here, because you'd have seen the rejection was never the subscription window.
Given the latest auxiliary-model signal, I would make this a resource-dependency envelope rather than a quota-message bug.
The invariant I would test is not just better error text. Every subagent run should carry:
The failure case to guard is a subagent burning context and tool work, then an auxiliary reviewer limiter killing it while the UI reports the session pool and /status shows the wrong state. That creates billed work with no recoverable output and no reliable way for the parent to know what actually stopped the run.
A conformance test could force the auxiliary reviewer/model unavailable while the parent session model still has quota. The expected result should bind the stop to the auxiliary limiter id, expose the same id in status and usage, and either checkpoint the subagent or mark consumed work terminal-no-effect/non-billable. If partial billing is allowed, the usage event should carry the same subagent_run_id and limiter_id as the terminal outcome.
That would separate user-side diagnosis from platform accountability: one envelope explains who stopped the run, what was charged, what is recoverable, and why the parent session continued.
The "reset time is a promise but actually a snapshot" problem gets worse at scale. When you have multiple background subagents running concurrently, the rolling window re-pins differently per subagent depending on when it actually consumed tokens, so each one can show a different reset projection - none of which are accurate for any of the others.
The underlying issue is that session limit accounting wasn't designed with concurrent subagent consumption in mind. Each subagent is effectively its own consumer drawing from the same pool, but the UI (and the error messages) treats it as a single-stream problem.
A few things that have helped in practice:
The behavior you're describing in point 4 (block persisting even after a supposed reset) is the most severe case - that reads like the rolling window refilled immediately from still-active consumption, which should at minimum surface a clear "you are still in an active consumption window" error rather than a new reset projection that also turns out to be wrong.
Worth adding: what was the approximate subagent token volume running concurrently when you hit the first limit error? Would help scope how much of this is "heavy concurrent load" vs. a pure accounting bug.
Exact volumes, from the workflow usage blocks:
Death 1 (06:08 PT, 'resets 8am'): a 13-agent workflow -- 12 concurrent verify agents had consumed 2,407,296 subagent tokens in the preceding ~7 minutes (414s wall clock); the 13th agent (the synthesis stage) was the one killed. So yes: ~2.4M tokens of concurrent burn immediately before the rejection.
Death 2 (11:38 PT, 'resets 2:10pm'): two workflows totaling 15 agents and 3,287,294 tokens had completed in the preceding ~35 minutes; the killed agent died at spawn, ~3 minutes in.
Death 3 (14:35 PT, 'resets 7pm') is the one the load theory can't cover: a single agent, zero concurrent fan-out, 374,904 tokens over 16.4 minutes, running on freshly purchased extra-usage credits, with /status showing subscription headroom -- killed mid-run with the same session-limit text. No pool it could plausibly have been drawing on was exhausted by concurrent load at that point.
On 'credits clearing the block is the expected behavior, not a workaround' -- agreed, that's the expectation. It's also what makes this a bug report rather than a usage complaint: the credit-funded agent died anyway. Credits did not clear the block; the second $50 purchase happened after death 3, not before it.
So I'd split the incident the way you implicitly did: deaths 1-2 are plausibly a real shared-window exhaustion made illegible by per-snapshot reset projections (your 'each subagent re-pins differently' point matches our 8am/2:10pm/7pm spread exactly). Death 3 -- solitary, modest-volume, credit-funded, /status-green -- needs a different explanation, and the only anomalous signal in the same window is the auxiliary-model unavailability ('claude-opus-4-8[1m] is temporarily unavailable...') hitting the main loop's safety classifier at 14:22 PT. That's why the auxiliary-dependency theory is still standing for the third rejection, and why @rpelevin's per-run envelope (rejection source bound to a limiter id, chargeability state, recovery state) is the right shape for the fix: it would have distinguished these three deaths from each other, which is precisely what the current error text cannot do.
Your checkpoint suggestion is adopted regardless -- phase-level state now gets written to disk before any multi-stage run, which is how deaths 1 and 3 cost redo-work instead of lost work.
---
Now before anyone chimes in here, assuming any of you are humans (ahem, I see right through the cross-cutting, load-bearing, honest honesty nonsense) I will be the first to admit I should count my lucky stars that I can dogpile and burn tokens like this for $200 a month. Having said that, @anthropics is learning, pressure testing, and productizing like a beast irrespective of whether I'm sharing training data explicitly or they're just shaping resources against my workloads.
For this kind of invisible subagent and session-limit behavior, here's a small tool. It reads Claude/Codex session data locally so you can inspect token usage and session details without API keys or shipping logs elsewhere.
Open source:
https://github.com/pzarzycki/token-companion
If you like it - leave a star; submit an issue or request, or even a PR!
Adding related Billing Platform / cost-control context because this thread already shows the expensive failure mode: a limiter/error path is ambiguous, purchased credits enter the flow, background work can die terminally, and consumed work may not be recoverable.
This is closely related to the broader paid-work-loss and wrong-pool accounting cluster:
Sanitized public evidence hub for the broader manual-credit, extra-usage, auto-topup, entitlement-routing, cost-control, and support-routing pattern: https://coolak.github.io/anthropic-claude-billing-incident/
Request: please route this class of reports to a human Billing Platform / cost-control owner. The product needs a shared runtime+billing event envelope that names the exact rejecting pool/model/gate, ties consumed usage to a recoverable artifact or checkpoint, and distinguishes billable-completed work from limiter-destroyed work that should be resumable, credited, or refunded.