Repository navigation
Description
What happened
About ten minutes after a usage-limited Claude thread had auto-resumed and finished its turn, the thread showed Limited in the sidebar again. The composer showed "Usage limit reached · Resets 10:21 PM" while the clock already read 10:32 PM. In the user's words: "this is weird because the datetime is past".
Diagnosis
A background-task wake turn hit the limit while no T3 turn was active. Its frames were buffered and replayed later, after the limit had reset and another turn had been served normally. The replay failed the continuation run as a fresh usage limit.
- The root turn hit the 5-hour limit (20:39 UTC) and its run failed with a usage limit. T3 armed auto-resume for the reset.
- A background task finished. Claude Code opened the wake turn itself and got a 429 (20:41): a
rate_limit_eventwithstatus: "rejected"andresetsAt1794604891, a<synthetic>"You've hit your 5-hour limit" assistant message, and an errorresult. No T3 turn was active, soClaudeAdapterV2buffered these frames (bufferWakeMessage; therate_limit_eventbranch buffers whenactiveTurnis null). The continuation run was queued behind the limit. - At the reset, auto-resume ran "Continue where you left off." (run 19, 21:21–21:31). It was served normally: its
rate_limit_events wereallowed, with 5h utilization at 0. - When run 19 ended, the queued continuation started (21:31:19.929). The adapter replayed the buffered frames into it. The
rate_limit_eventbranch put the old rejection incontext.rejectedRateLimitTypesandrateLimitResetTimesand emittedusage-limit:…:five_hour:1794604891(around line 10008 at bc7fe11). The replayedresultthen failed the run through theusageLimitedpath (around line 11263). The run failed at 21:31:20.059, 130 ms after it started, without a single upstream request. ItsresetAt(21:21:31) was already ten minutes in the past.
The web side shows the stale state as is. usageLimitRecoveryBannerItem hides the actions when resetAt <= stoppedAt, but it still renders "Usage limit reached · Resets ". The thread list counts the thread as Limited until another turn starts.
Expected: a buffered rejection whose resetsAt has passed by replay time does not fail the continuation as a usage limit or put the thread back into the limited state. This applies especially when a later turn on the same native thread has already been served with allowed limits.
The adapter code is unchanged on main @ bc7fe11 (2026-11-13). File and line references are from main, not the nightly tag.
Steps to reproduce
- On a Claude subscription login, start a thread whose turn launches a background task (
run_in_backgroundBash) that outlives the turn. - Let the turn hit the 5-hour limit, so the run pauses with auto-resume armed.
- Let the background task finish before the reset. Claude Code opens the wake turn on its own, and it is refused with a 429 while no T3 turn is active.
- Wait for the reset. Auto-resume runs a new turn, and it succeeds.
- When that turn ends, the queued wake continuation starts and fails at once as a usage limit with the old, already past reset.
The same buffering path as #25021 should reproduce it in a test: buffer a rejected rate_limit_event, its synthetic message and the result while idle, advance the clock past resetsAt, run a served turn, then start the continuation.
Version
0.1.10-nightly.20261113.4643 (background service, t3 serve)
Environment
Arch Linux (headless server, background service), Claude Code 2.1.325, Claude Fable on a subscription login
Evidence
# provider event log; wake turn while no T3 turn was active (buffered)
[2026-11-13T20:41:14.121Z] {"type":"rate_limit_event","rate_limit_info":{"status":"rejected","resetsAt":1794604891,"rateLimitType":"five_hour","unifiedWindows":{"five_hour":{"utilization":1,"resetsAt":1794604891,"status":"rejected"}}}}
[2026-11-13T20:41:14.124Z] {"type":"assistant","message":{"model":"<synthetic>", ...}} # "You've hit your 5-hour limit"
[2026-11-13T20:41:14.126Z] {"stop_reason":"stop_sequence", ...} # result
# auto-resume turn (run 19), served normally
[2026-11-13T21:21:40.271Z] {"type":"rate_limit_event","rate_limit_info":{"status":"allowed","resetsAt":1794622800,"rateLimitType":"five_hour", ...}}
[2026-11-13T21:31:18.130Z] {"stop_reason":"end_turn", ...} # run 19 result
# no provider frames between 21:31:18.135 and 21:31:22.305, yet:
orchestration_v2_projection_runs ordinal 20 requestedAt 20:39:13.110Z startedAt 21:31:19.929Z completedAt 21:31:20.059Z status failed
turn item usage-limit:…ordinal%3A18%3Aattempt%3A1:five_hour:1794604891 21:31:19.982Z "Claude usage limit reached. This turn is paused until the 5-hour limit resets."
turn item assistant_message 21:31:19.982Z "You've hit your 5-hour limit · resets 10:21pm (Europe/Berlin)"
turn item error "Usage limit reached" 21:31:20.019Z "Claude API rate limit reached. Try again later."Related issues
#25021 fixed the reset base of a replayed wake result and explicitly left this open: "The stale failure is still recorded on that continuation run, which is a separate question." This issue is that question. It is not #33708 (Codex: the provider refuses the continuation right after the reset); here no request is made at all.
Fix applied or workaround
Nothing was changed on the machine. The next turn on the thread (any message or wake) cleared the banner and the Limited badge.
Filed by
Claude Code (Claude Opus 5.5), investigating on the user's machine at their request. This followed the triage playbook but did not go through t3 triage. I can't apply the via-triage label: the account has no triage permission.
Activity
[-][Bug]: A replayed Claude wake fails its continuation with a usage limit whose reset has already passed[/-][+]A replayed Claude wake fails its continuation with a usage limit whose reset has already passed[/+]fix(server): ignore expired buffered Claude wake limits
fix(server): ignore expired buffered Claude wake limits
docs(evidence): record 424 passing checks on current main for pingdot…