You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: Claude 429 with no reset time fails delegated runs with no recovery #22619
I searched existing issues and did not find a duplicate.
I included enough detail to reproduce or investigate the problem.
Area
apps/server
Steps to reproduce
Start several delegated Claude tasks close together (for example via delegate_task reviews) on an account near its rate limit.
Let Claude return HTTP 429 without a reset time.
Expected behavior
A rate-limited run whose failure is marked retryable: true is either retried later or offered the same limit-recovery path as a run with a known resetAt.
Actual behavior
The run fails terminally with {"class":"usage_limit","message":"Claude API rate limit reached. Try again later.","code":"api_error_429","retryable":true,"resetAt":null}. Limit recovery in Orchestrator.ts is only set up when failure.resetAt is a valid date, so with resetAt: null nothing resumes the run and the delegating thread receives a failed task.
Local data from one machine: 13 of 66 Claude runs (20%) failed this way between 2026-10-19 05:52 and 22:55 UTC, all of them delegated tasks. None were retried or resumed.
I have not established whether the Claude Agent SDK had already retried internally before reporting the terminal 429; if it had, the request is only for a recovery path when the reset time is unknown.
Impact
Major degradation or frequent failure
Version or commit
Installed build: t3code-bin 0.1.0 (built 2026-10-15). Code checked on main at ecfe4f7.
Thanks for the numbers. This is how limit recovery is designed today. Auto-resume is scheduled against the reset time Claude reports. A failed thread only becomes a recovery candidate when its usage limit failure carries a resetAt (apps/server/src/orchestration-v2/UsageLimitRecoveryWorker.ts:16-25, and the candidate query in apps/server/src/orchestration-v2/ProjectionStore.ts filters on it too). With resetAt: null there's nothing to schedule against, so the run stays failed, and the thread shows that the reset time is unavailable and to retry manually. A delegated task that fails this way reports the failure to its parent like any other.
So this isn't a bug in recovery, but the gap is real: a retryable 429 with no reset time gets no automatic retry at all. Retrying those later, for example with a backoff when the reset is unknown, would be new behavior, and it would need care so a busy account doesn't keep re-sending. Closing as not planned for now. Please raise that in Ideas: https://github.com/pingdotgg/t3code/discussions/new?category=ideas
This is separate from #22026 and #22063, which cover a reset time Claude reports but then refuses at.
Activity
juliusmarminge commentedon Oct 21, 2026
Note
Grok responding on behalf of Julius.
Thanks for the numbers. This is how limit recovery is designed today. Auto-resume is scheduled against the reset time Claude reports. A failed thread only becomes a recovery candidate when its usage limit failure carries a
resetAt(apps/server/src/orchestration-v2/UsageLimitRecoveryWorker.ts:16-25, and the candidate query inapps/server/src/orchestration-v2/ProjectionStore.tsfilters on it too). WithresetAt: nullthere's nothing to schedule against, so the run stays failed, and the thread shows that the reset time is unavailable and to retry manually. A delegated task that fails this way reports the failure to its parent like any other.So this isn't a bug in recovery, but the gap is real: a retryable 429 with no reset time gets no automatic retry at all. Retrying those later, for example with a backoff when the reset is unknown, would be new behavior, and it would need care so a busy account doesn't keep re-sending. Closing as not planned for now. Please raise that in Ideas: https://github.com/pingdotgg/t3code/discussions/new?category=ideas
This is separate from #22026 and #22063, which cover a reset time Claude reports but then refuses at.