Skip to content

[Bug]: A thread waiting on background work stays stranded after a backend restart until the user sends a message #15358

Closed as not planned

Description

@allisonmahmood

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server

Summary

A Claude agent can end its turn waiting on a background task (run_in_background) and rely on the completion notification to wake it. If the backend dies in the meantime, the task dies with the agent process. Recovery records exactly what was lost, but the thread stays idle and looks finished. The agent only learns about it when the user next sends a message. In our case a triage thread sat like that for 27 minutes until I noticed it was stuck.

Visual explainer with the full timeline: https://post.patchyhq.com/d/078j555zejie

Steps to reproduce

  1. In a Claude thread, ask the agent to start until [ -e /tmp/release-b ]; do sleep 1; done with run_in_background: true, then end its turn and wait for the notification.
  2. Once the turn has ended, kill -9 the backend from a terminal outside T3 (its pid is in ~/.t3/userdata/server-runtime.json). Let the desktop restart it.
  3. touch /tmp/release-b and wait.

"Continue threads after restarts" is at its default (off).

Expected behavior

The thread is woken with the cancellation note, or at least shows that its background work was lost.

Actual behavior

The run stays completed and the thread stays idle indefinitely. Recovery stored the loss correctly on the run straight away:

restartCancelledBackgroundWork: [{"kind":"shell","label":"Wait for release-b then record time (id b6w74smo0)","id":"b6w74smo0"}]

Nothing woke the thread. In the original incident, the note reached the agent only when I nudged it 27 minutes later:

Note: the T3 server restarted, and this background work was cancelled before it finished. It will not report back: - shell: Wait for codex trace to finish (id btuwr7ruo)

Cause

  • RestartBackgroundNote.ts:87 builds the note, and ProviderTurnStartService.ts:1127 prepends it to the next user input.
  • The automatic path exists (ProviderRuntimeRecoveryService.ts:635 → RestartContinuation.ts:120), but it is gated on continueThreadsAfterServerUpdate, which defaults to false (packages/contracts/src/settings.ts:1206).

An agent that ended its turn waiting on a task has handed control to that task's notification. Waiting for the user is always wrong in that case, whatever the setting.

The same blind spot affects orchestration. t3_thread_wait returns once the latest run is terminal (ThreadManagementService.ts:610), and t3_thread_read doesn't expose pendingBackgroundTasks (orchestrationV2.ts:831). Our orchestrating thread got completed for this child while it was still waiting on its codex job, and had no way to see that the child had been stranded.

Possible fix

  • When recovery cancels a thread's background tasks, always continue that thread with the note, whatever the setting. If that's too aggressive, show a "background work lost" state in the sidebar.
  • Return pendingBackgroundTasks and restartCancelledBackgroundWork from t3_thread_read and t3_thread_wait, so orchestrators can tell "done" from "waiting" and "stranded".

Related

Impact

Major degradation or frequent failure

Version or commit

0.0.46-nightly.20261003.2632 (f391794), Orchestrator V2

Environment

Linux 7.2.5 (Arch-based), desktop AppImage, Claude Code 2.1.288 via Agent SDK 0.3.276, Claude Opus 5.5

Workaround

Turn on Settings → General → "Continue threads after restarts", or send any message to threads that were waiting when the backend restarted.

Related reports from the same incident: #15357 (agents that were mid-turn survive the crash and keep working, unseen), #15359 (a killed backend is logged as "Failed to read the exit status").

Filed by Allison Mahmood. Investigated and drafted with Claude Opus 5.5 in Claude Code.

Activity

  1. juliusmarminge commented on Oct 3, 2026

    @juliusmarminge
    Member

    Note

    Grok responding on behalf of Julius.

    Triage

    Thanks for the clear repro and timeline, @allisonmahmood! This reproduces on current main with "Continue threads after restarts" at its default (off). Open PR #15323 only delivers this note when that setting is on, so it doesn't cover this case.

    What happens

    Startup recovery always clears the provider-thread roster and writes run.background-work-cancelled. That's the restartCancelledBackgroundWork row in your report. It only enqueues provider-runtime.continue when continueThreadsAfterServerUpdate is on for the project, and continueRestartedRun checks the same setting again, so with the default nothing is sent.

    A turn that had already finished then stays completed. Nothing in the web UI reads restartCancelledBackgroundWork, and clearing pendingBackgroundTasks removes the only "still working" signal, so the thread looks idle. ProviderTurnStartService adds the note to the next user turn, which is why it only showed up after your nudge.

    The wake itself already exists. A completed or waiting run that lost background work is continued with the cancellation note, and the setting is the only gate.

    The t3_thread_read / t3_thread_wait gap is real but separate. Wait returns once the latest run is terminal, and neither result includes pendingBackgroundTasks or restartCancelledBackgroundWork. A parent can see a child as done while it's still waiting on a background command, even without a restart. That's the same blind spot as #15099.

    Likely fix area

    • One option is to always continue a thread that lost background work, even with the setting off. That unblocks an agent that ended its turn waiting on a notification, but it would also resume threads that just left a long-running command behind.
    • Another is to keep the setting as the only automatic path and show the stored cancellation in the UI, so the loss is visible without starting a turn.
    • The orchestration side, exposing background state from t3_thread_read and t3_thread_wait, could be handled separately.

    This isn't a duplicate of #15235, #15357, or #15359. Your workaround is the right one for now. A maintainer will decide on the fix direction.

  2. added
    bugSomething is broken or behaving incorrectly.
    via-triageFiled through npx t3 triage
    on Oct 3, 2026
  3. SunkenInTime commented on Oct 4, 2026

    @SunkenInTime
    Contributor

    I opened #15438 to wake these threads even with Continue threads after restarts off, and I'm closing it. Two reasons:

    1. A restart is usually an update. Every thread with a lingering dev server or Monitor would start a turn at the same moment, without the user asking. Controlling that is what the setting is for.
    2. The note tells the agent its work was cancelled, and that isn't reliable yet. On Linux and macOS the agent itself can survive a SIGKILL ([Bug]: Backend crash leaves Claude agents running after their runs are marked cancelled #15357). On Windows I saw claude.exe die with the server while the background command it had started kept running.

    Proposal: keep automatic continuation opt-in and make the loss visible instead.

    Does that direction work for you? If so I'll build it. #15438 also had two fixes that apply when the setting is on: a settle racing a restart continuation could reopen the thread, and a Stop followed by a steer blocked recovery of the steered attempt. I can send those as a separate PR.

  4. t3dotgg commented on Oct 21, 2026

    @t3dotgg
    Member

    Note

    🤖 Claude Opus 5.5 responding on behalf of Theo

    Thanks for the report. This behavior is intended, so we will not change it. If you need different behavior, please post the idea in Ideas discussions so others can vote on it. If you see a different fault, please open a new issue with steps to reproduce it.

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

    bugSomething 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