[Bug]: Claude session exits when a background Bash task stops after its turn completed
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 23k
- Forks
- 5.9k
- Avg merge
- 11h 14m
- Merged PRs (30d)
- 357
Description
Before submitting
- I searched existing issues and did not find a duplicate.
- I added enough detail to help find the cause.
Area
apps/server
Steps to reproduce
- Start a Claude thread in the desktop app with full access.
- Ask Claude to start a long Bash command with
run_in_background: trueandtimeout: 600000. - Let the foreground turn finish while the Bash task keeps running.
- Wait for the Bash task to end as failed or killed.
I saw this twice with a Bash task that started a child process and waited for it. I have not reduced it to a short command yet.
The tasks stopped before their declared ten-minute timeout. One ran for about five minutes and forty-two seconds. The other ran for about seven minutes and fourteen seconds.
Expected behavior
T3 should mark the background task as failed or cancelled. The Claude session should stay ready, or restart on the next message.
A failed background command should not end the provider session. The foreground turn had already completed.
Actual behavior
T3 receives the background task's stopped and failed events. Less than one second later, it emits Claude runtime stream failed. and closes the Claude session.
The foreground Claude turn had completed successfully several minutes earlier. The same long job does not use this Claude adapter path when Codex owns the thread.
Impact
Major degradation or frequent failure
Long background jobs can die without their requested timeout being reached. The thread then shows a provider error and needs a new Claude session.
Version or commit
T3 Code 0.0.38
Environment
macOS 26.6.2, build 25G83, Apple Silicon, T3 Code desktop 0.0.38, Claude Code 2.1.260, Claude Opus 5 with the one-million-token context option, full-access runtime.
Logs or stack traces
# First occurrence
12:06:57 claude/result/success, foreground turn completed
12:12:34 claude/system/task_notification, status: stopped
12:12:34 claude/system/task_updated, status: failed
12:12:35 runtime.error, message: "Claude runtime stream failed."
failureTags: ["ProviderAdapterProcessError"]
12:12:35 session.exited, reason: "Session stopped", exitKind: "graceful"
# Second occurrence
13:50:41 claude/result/success, foreground turn completed
13:57:53 claude/system/task_notification, status: stopped
13:57:53 claude/system/task_updated, status: killed
13:57:54 runtime.error, message: "Claude runtime stream failed."
failureTags: ["ProviderAdapterProcessError"]
13:57:54 session.exited, reason: "Session stopped", exitKind: "graceful"
# server.trace.ndjson for the second occurrence
claude.turn.result-without-active-turn
status: failed
hasUsage: false
errorMessage: "Claude runtime stream failed."
The bundled adapter maps any rejected Claude SDK stream to ProviderAdapterProcessError with the fixed detail Claude runtime stream failed.. The runtime event keeps only the failure count and tag, so the child process cause is lost.
Raw logs are not attached. They contain local paths, private commands, and authentication data.
Workaround
Starting a new Claude session recovers the thread. Avoiding run_in_background, or setting CLAUDE_CODE_DISABLE_BACKGROUND_TASKS=1, avoids this path but removes background work.
Suggested fix
Keep a failed or killed background task scoped to that task when no foreground turn is active. Stop or restart the idle Claude session without reporting a turn failure. Also retain the underlying SDK or child process cause in the redacted server log.
Related but different: #4198 covers the thirty-minute idle reaper. These two failures happened in less than eight minutes.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in apps/server by tracing the bundled Claude adapter's rejected SDK stream handling and the runtime events for stopped or failed background tasks. Reproduce the sequence with a completed foreground turn and a background task that ends as failed or killed. Done means the task remains scoped to itself, the idle session does not report a turn failure, and the underlying cause is retained in redacted server logs.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 52/100