Skip to content

[Bug]: Cancelling a usage-limited delegated task leaves its reset arm active and revives a superseded child #21091

Closed

Description

@raffareis

Summary

An app-owned Claude delegated task was cancelled after hitting its usage limit and being replaced by a task on another account. The cancellation was recorded, but the previously armed quota reset still dispatched a new child run about 19 minutes later. That stale run executed the superseded brief and local checks while the parent had explicitly held new execution.

Observed on Linux, active server executable 0.1.1-nightly.20261017.3238, using T3 MCP delegate_task, task_cancel, task_status, and the durable thread timeline. No new reproduction job was started for this report.

Observed sequence (2026-10-18)

Event UTC America/Sao_Paulo (UTC−3)
Original delegated run started 03:49:47.631 00:49:47.631
Structured five-hour usage limit recorded; reset at 04:10Z 03:50:11.695 00:50:11.695
Original run failed with rate limit 03:50:14.816 00:50:14.816
Parent cancellation recorded as Interrupt requested, with reason to prevent automatic resumption after replacement 03:51:18.658 00:51:18.658
Server-generated Continue where you left off. message dispatched by limit-resume:...:limit-arm:... 04:10:05.856 01:10:05.856
Unwanted continuation started 04:10:13.828 01:10:13.828
Unwanted continuation completed 04:15:30.676 01:15:30.676

Original task client request ID: pilotos-robo-1387-painel-geracoes-opus-v1. The child thread is the corresponding app-owned thread:delegated-task:command:mcp:...:delegate-task:<clientRequestId>; original run ordinal 1, automatic continuation ordinal 2. The automatically created task has the node:delegated-task:limit-resume:...:limit-arm:... prefix and retains the original run/arm identity.

Expected

Cancelling an app-owned delegated task must stop/hold its queued continuations and invalidate every pending usage-limit resume arm for its child thread, even if the original run is already terminal (failed due to quota). A replaced/cancelled task must not be revived by the reset timer. The child should only resume after a fresh explicit action.

Actual and impact

The child was revived by a server-generated user message after the cancellation. It followed the old brief, made one local commit, and ran local tests and type checks. The original task still reports failed; its latestTerminalRunId points to completed ordinal 2. After a second explicit cancellation and reconciliation, hasPendingChildRuns=false, hasPendingQuestion=false, the backing thread is terminal with activeRunId=null.

The unwanted turn lasted 316.848 seconds. One initial test invocation reported 30 tests / 648 ms; further test reruns and at least four tsc invocations were recorded. CPU, RSS, tokens and financial cost were not exposed in the retrieved evidence and are unknown, not zero. Filtered type-check output is not proof of a globally successful type check.

Investigation pointers

The durable timeline demonstrates both the parent run_interrupt_request and the later creationSource=server quota-resume message. Please check arm invalidation when cancelling a task whose original run has already become terminal, and re-check cancellation/replacement state immediately before dispatching a reset arm. Related but different symptoms: #16815 and #17808.

No credentials, source code, private filesystem content or user data are included in this report.

Activity

  1. raffareis commented on Oct 18, 2026

    @raffareis
    Author

    A second independently observed occurrence of the same failure was reconciled by another parent coordinator (no new reproduction run):

    • Delegated task request: admin1396-1398-revisao-opus-r1-1018.
    • Backing child thread: thread:delegated-task:command%3Amcp%3Adbf39380-940a-44ef-a259-6000e348399e%3Adelegate-task%3Aadmin1396-1398-revisao-opus-r1-1018.
    • Original ordinal 1 hit quota at 2026-10-18 04:08:46Z (01:08:46 BRT).
    • task_cancel recorded an interrupt request at 04:09:41.855Z (01:09:41.855 BRT), explicitly saying not to resume.
    • Nevertheless ordinal 2 was requested at 04:10:03.921Z, started 04:10:13.016Z, and completed 04:16:19.347Z (01:10:03.921 / 01:10:13.016 / 01:16:19.347 BRT).
    • Unwanted provider turn duration: 366.331 seconds. This occurrence performed read-only review; no jobs, tests or browser execution were reported. CPU/RSS/token/financial cost remains unknown.
    • Original task_status still reports status=failed, hasPendingChildRuns=false, but latestTerminalStatus=completed points to ordinal 2. Parent reconciled the result and cancelled again; no duplicate reviewer remains active.
    • Evidence source: durable t3_thread_read activity/recentRuns and task_status, reported by that task's owning coordinator.

    This is a second observation, not proof of root cause. Both show cancellation preceding server quota-reset dispatch, including cancellation only about 22 seconds before reset in this case. Useful review results were preserved rather than rerun.

  2. juliusmarminge commented on Oct 18, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Accepted as a bug, confirmed on current main. When the task's run has already failed on a usage limit, task_cancel stops the child thread, which records an interrupt request on that failed run. It does not clear the thread's pending limit resume. The limit-recovery sweep and the check before the server sends "Continue where you left off." look at archive, settle, snooze and pending requests, but never at that interrupt request. Restart continuations already skip a run that Stop reached, but limit resumes don't. So a reset that fires after a cancel still starts a new run. Your timeline matches that path. Neither open usage-limit PR changes it.

  3. added
    acceptedfeature request accepted
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 18, 2026
  4. t3-code commented on Oct 21, 2026

    @t3-code
    Contributor

    closing as addressed by #21114, merged into main: Stop persists a disarmed usage-limit recovery record, including cancellation before automatic arming. A stale recovery sweep cannot overwrite that choice and revive the cancelled child; explicit Resume at reset can arm it again.

    thanks for reporting this. if you still face it on a build containing this fix, please ask us to reopen this issue or open a new issue linking back here, with your version, os and reproduction steps.

    closed at the request of @UtkarshUsername.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedfeature request acceptedbugSomething is broken or behaving incorrectly.via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions