Repository navigation
[Bug]: A Claude subagent resumed after T3 missed its launch never gets a child thread, so opening it shows "Thread unavailable" #18319
Description
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
Steps to reproduce
- In a Claude thread, have the parent launch a background subagent (Agent tool,
run_in_background: true) while T3 is not ingesting that run. In my case the disk filled up (ENOSPC), and T3 recorded nothing more for the long-running parent run even though the Claude CLI kept working for hours. The parent launched two subagents during that gap. Any gap where T3 misses the Agent launch should behave the same way. - Interrupt the run, then start a new turn in which the parent resumes those subagents with
SendMessage. - Open the Agents panel and tap one of the resumed subagents (or open its child thread from web).
Expected behavior
The resumed subagent opens a child thread that shows its work. At minimum, T3 creates the child thread the subagent card points at.
Actual behavior
The Agents panel lists the subagents as Working, with live progress. Tapping one on iOS shows "Thread unavailable — This thread is not available in the current mobile snapshot." with a "Reconnect environment" button that can't help.
The orchestration_v2_projection_subagents rows have a child_thread_id, but no row in orchestration_v2_projection_threads has that ID. 24 other Claude subagents in the same thread all have their child threads. Only the two resumed after the missed launch are missing them.
Cause, from the source at ac2cc78:
- When
SendMessageresumes a task id the session doesn't know,recoverResumedClaudeSubagent(apps/server/src/orchestration-v2/Adapters/ClaudeAdapterV2.ts~L4368) registers it as a finished subagent withchildThread: null. It assumes the launch happened before a server restart and that the child thread already exists ("same child thread, launch prompt kept"). - The reopen then runs through
updateClaudeSubagentNodewithexistingSubagentdefined. Theapp_thread.createdemission (~L5053–5081) is gated onexistingSubagent === undefined, so it is skipped. - If T3 never saw the original launch, nothing ever creates the child thread. The subagent's
childThreadIdpoints at a thread that doesn't exist.
The persisted rows match the recovery path: neither resumed subagent has modelSelection, which the recovery registration omits. Their startedAt values equal the timestamps of the two SendMessage tool calls in the resuming run.
A possible fix: when a recovered subagent reopens, create its child thread if it is missing. This should be create-only. The normal app_thread.created path turns into thread.metadata-updated when the thread exists, and that would overwrite an existing child thread's title and model with the parent's selection in the usual restart case.
Related but distinct: #16261, where the child thread exists but stops receiving items after a resume. Here the thread is never created at all.
Impact
Major degradation or frequent failure
Version or commit
Desktop 0.0.46-nightly.20261011.2955 (server host); iOS 2.0.0 (114) client. Source references at main ac2cc78.
Environment
macOS desktop app as the host, iOS app connected to it. Claude Code 2.1.296, claude-opus-5-5 parent and subagents.
Logs or stack traces
# orchestration_v2_projection_subagents for the parent thread (child_exists = row in projection_threads)
task status run child_exists
... completed ordinal:1 1 (x4)
... completed ordinal:2 1 (x6)
a3c7388aabe4c4108 completed ordinal:13 1
... interrupted ordinal:16 1 (x5)
a8e0071d9d9b60582 running ordinal:21 0 <- resumed via SendMessage
ae3f3ef0894e84172 running ordinal:21 0 <- resumed via SendMessage
# Timeline (UTC)
10:24:08 last turn item T3 stored for parent run 19 (parent CLI hit ENOSPC at 10:24:08)
17:30:46 parent CLI launches Agent a8e0071d9d9b60582 (toolu_014N...), not recorded by T3
17:30:50 parent CLI launches Agent ae3f3ef0894e84172, not recorded by T3
17:48:44 run 19 interrupted
17:57:45 run 21: SendMessage -> a8e0071d9d9b60582; subagent startedAt 17:57:46.016
17:57:48 run 21: SendMessage -> ae3f3ef0894e84172; subagent startedAt 17:57:48.406Workaround
Read the subagent transcript from ~/.claude/projects/<project>/<session>/subagents/agent-<id>.jsonl.
Activity
juliusmarminge commentedon Oct 11, 2026
Note
Grok responding on behalf of Julius.
Confirmed on main (bed9239). When
SendMessageresumes a task the session doesn't know,recoverResumedClaudeSubagent(ClaudeAdapterV2.ts~L4369) registers it withchildThread: null, which assumes the child thread was created at launch. The later reopen goes throughupdateClaudeSubagentNodewithexistingSubagentdefined, andapp_thread.created(~L5074) only fires whenexistingSubagent === undefined. So if T3 never saw the original Agent launch, nothing creates the child thread, and the subagent'schildThreadIdpoints to a thread that doesn't exist.ENOSPC is an unusual way to trigger this. The recovery path itself still assumes the thread exists without checking. Your suggested fix is the right shape: on recovery, create the child thread only if it's missing, and leave existing threads alone so a normal restart doesn't overwrite their title or model.
This is separate from #16261, where the thread exists but stays empty, and from #17596, which covers looking up the launch on instances with their own home directory.