[BUG] run_in_background task-notification routed to wrong session/project
What's Wrong?
A background task (launched via the Bash tool's run_in_background: true) sometimes never delivers its completion notification to the session that launched it. Instead, the <task-notification> is queued and delivered to a different, unrelated session — one that happens to be active when the task finishes, in a directory that isn't even the same project as the one the task ran in.
From the session's perspective that launched the task, it just looks like the background shell is "hung forever" — /tasks (or asking the agent to check) shows it as still running, with no way to know the notification already fired somewhere else.
What Should Happen?
Either:
- The completion notification should be delivered to (or remain visible/queryable from) the session that actually launched the task, regardless of whether that session is still the "active" one, or
- If cross-session delivery is intentional (e.g. so a new session in the same project can pick up in-flight work), it should at minimum be scoped to the same project directory the task was launched in — not delivered into a session working in a completely different, unrelated project.
Steps to Reproduce
- Start a Claude Code session in project directory A, launch a long-running command in the background (
run_in_background: true). - End that session (or let it go idle) before the command finishes.
- Start a new Claude Code session — in a different, unrelated project directory B.
- Wait for the background command from step 1 to finish.
- The
<task-notification>for the step-1 task is delivered into the new session in project B, not into the original session A (which never receives it and, if reopened, still shows the task as unresolved).
I found this by grepping my own local session transcripts (~/.claude/projects/**/*.jsonl) for a run_in_background launch whose task id never resolves in the same transcript. Concrete instance from my own logs (paths/project names redacted, mechanism preserved):
- Session A (
cwd: project X) launches a background command atT+0s; getsbackgroundTaskId: <id>. - Session A's turn ends normally ~67s later (clean stop-hook + turn_duration, not a crash) — no notification for
<id>ever appears in session A's transcript. - A different session B (unrelated
cwd: project Y, a completely different repo than project X) receives aqueue-operation: enqueueentry for<task-notification><task-id><id></task-id>...<status>completed</status>...about 6 minutes later — followed immediately by aqueue-operation: remove. - Session A never sees this. If a user doesn't happen to have another session open in exactly the right place at exactly the right time, the notification is effectively lost from their point of view.
Claude Code Version
2.1.205 (Claude Code) — issue was captured on 2.1.204, reproducible mechanism (notification queue keyed loosely, not to the launching session) appears unchanged in 2.1.205.
Is this a regression?
I don't know
Platform
Anthropic API
Operating System
Windows
Terminal/Shell
PowerShell
Additional Information
This may be the underlying cause of a broader, frequently-reported symptom: background shells that appear to "hang" or never complete from the user's perspective, even though the underlying command finished normally (exit code 0 in the case I traced). If task-notification routing is keyed off something like "whichever session is currently active" rather than the session (or at least the project) that launched the task, that would explain reports of background tasks silently never resolving — the resolution happened, just not where the user was looking.
3 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
Additional evidence, this time a cleaner single-session repro rather than the cross-session one above:
run_in_background: true) — a multi-step build/test/install script that takes a couple of minutes.<task-notification>for it in the same session that launched it, with<status>completed</status>and exit code 0./exit). The exit-confirmation dialog still listed that shell as "running" and warned it would stop if I exited, even though I'd already received and processed its completion notification in this exact session.Get-CimInstance Win32_Processfiltered for the script in question) — zero matching processes were alive. The underlying work had genuinely finished.So this isn't just the cross-session routing issue described above — there's also a same-session desync between "task completion was already delivered/processed" and the background-task tracker used by the exit-confirmation prompt, which doesn't get cleared even when nothing is actually running anymore.
Not a duplicate of any of the three flagged — those are all specifically about the
Agenttool's subagent/orchestrator system (area:agents: worktree-isolated agents, nested agent spawning, parent-child agent ID confusion). This report involves no agents or subagents at all — it's the plainBashtool'srun_in_background: trueon two fully independent, sequential top-level CLI sessions with no spawn relationship, launched minutes apart in unrelated project directories.It's possible both symptoms trace back to the same shared task-notification queue/dispatch infrastructure underneath both features, which would make these worth cross-referencing — but this is a distinct entry point (plain background shells, not agents) and shouldn't be auto-closed as a duplicate of an agent-specific bug.