Background Task Notifications Not Delivered When Multiple Agents Complete Simultaneously (v2.1.19)
Bug Description
When running multiple background agents (run_in_background: true) in parallel, completion notifications are not consistently delivered to the main session. Only 1 out of 3 agents sent a notification upon completion.
Environment
- Claude Code Version: 2.1.19
- OS: macOS Sequoia 15.2 (Darwin 25.2.0)
- Model: claude-opus-4-5-20251101
- Terminal: iTerm2
Steps to Reproduce
- Launch 3 background agents simultaneously:
Task({
subagent_type: "general-purpose",
description: "Task 1",
prompt: "...",
run_in_background: true
})
// Repeat for Task 2 and Task 3
- While agents are running, send a user message (e.g., "checking status")
- Wait for all agents to complete
Expected Behavior
All 3 agents should deliver <task-notification> messages upon completion.
Actual Behavior
- Agent 1 (a34bb07): ✅ Notification received
- Agent 2 (a0fc025): ❌ No notification (but completed successfully)
- Agent 3 (a194492): ❌ No notification (but completed successfully)
All agents completed successfully (verified via tail on output files), but only 1 notification was delivered to the main session.
Evidence
Output files confirm completion:
$ grep -c "stop_reason" ~/.claude/projects/.../subagents/agent-*.jsonl
agent-a0fc025.jsonl:22 # Completed
agent-a194492.jsonl:41 # Completed
agent-a34bb07.jsonl:42 # Completed (notification received)
Suspected Cause
Race condition in notification queue processing:
- Multiple agents complete around the same time
- User sends a message while notifications are queued
- Queue processing is interrupted or notifications are "swallowed"
Workaround
Manually check agent output files:
tail -20 /private/tmp/claude/-Users-*/tasks/*.output
Or wait a few seconds after agents complete before sending any messages.
Impact
- Users cannot reliably track background task completion
- Workflow automation based on notifications becomes unreliable
- Parallel agent execution loses observability
Related
This may be related to the notification queue handling introduced in v2.1.16+ with the new task management system.
---
Thank you for looking into this! Happy to provide additional logs or context.
Showing cached comments. Read the full discussion on GitHub ↗
4 Comments
This notification delivery bug is brutal for multi-agent workflows. If you can't rely on completion notifications, you're back to polling - which defeats the whole point of background agents.
The Root Problem
Claude's internal notification system is:
When multiple agents complete simultaneously, the notification queue likely gets overwhelmed or race-conditions occur.
External Notification Layer
We built ForkOff specifically to solve unreliable internal notifications:
How It Works
Instead of relying on Claude's stdout for notifications:
Architecture Benefits
Decoupled from Claude:
Webhook-based:
Guaranteed delivery:
Use Case: Your 3-Agent Scenario
With current system:
With external notifications:
Beta Access
Just launched: https://forkoff.app (TestFlight)
Workaround Until Claude Fixes This
Add webhook calls to your agent completion logic as a safety net. Even when Claude's notifications work, you get redundant external notification.
When they fail (like this bug), external system is backup.
---
Disclosure: I work on ForkOff. Built this after hitting the same "where's my notification?" frustration.
More evidence.. Same root symptom, confirmed across 2.1.170 through 2.1.178.
What's Wrong?
A completed background/async task intermittently fails to resume the agent waiting on it. Two observed manifestations, same user-visible result:
Either way the waiting agent hangs indefinitely until killed or manually nudged. It is load-dependent: the more tasks complete near-simultaneously, the higher the failure rate.
What Should Happen?
Every completed task resumes the agent that launched it, exactly once, in that agent's own context.
Error Logs/Messages
Manifestation (b): minimal repro, two sibling agents on v2.1.170, identical
sleep 15 && echotask, diverging only at resume:| | healthy agent | stuck agent |
|---|---|---|
|
Bashissued | 16:07:49 | 16:07:51 || TOOL_RESULT delivered | 16:08:04
MARKER_1(is_error:false) | 16:08:06MARKER_4(is_error:false) || resumed to next turn | 16:08:06
"MARKER_1 done"(ok) | never; stalled 6 min until process timeout |The stuck agent's successful tool result is present in its transcript; the loop was simply never re-invoked. No rate-limit/429/quota/error anywhere in its transcript or stderr.
Manifestation (a): main-session queue log (v2.1.177), completion
removed without delivery, then surfacing inside a sibling:Steps to Reproduce
run_in_background) at once, each doing a short identical task (e.g.sleep 15 && echo MARKER_<n>), then instruct the launcher to wait for all completions.-pruns, the stalled child is eventually killed by timeout (exit 124).Objective check (do not trust the model's narration): in the session JSONL, grep
queue-operationentries with"operation":"remove"on a<task-notification>; and scansubagents/agent-*.jsonlfor a<task-notification>whosetask-iddoes not match that file's agent id but is an agent the main session launched. Either is a confirmed instance.Last Working Version
2.1.152, the most recent version I have observed working with background agents (17 launches across 3 sessions, 0 failures). The bug is present in 2.1.170, 2.1.177, and 2.1.178. I have no background-agent usage between 2.1.153 and 2.1.176, so the exact regression point is unknown.
Additional Information
Regression data from v2.1.211 (controlled drills, interactive harness, macOS): background-Bash park-wake delivery has degraded from "unreliable" to effectively zero.
Setup: subagents pinned
model="sonnet"under an Opus main, each running a shortsleepviaBash run_in_background=trueand ending their turn parked. Verified from the agent JSONL transcripts (presence/absence of theisMetabackground-task wake event), not from agent self-reports.claude -p(same version): parked subagents never wake on either channel — neither a background-Bash completion nor a child-agent completion resumes them, whether the headless main is blocked in one long tool call or idling across many short ones. They stay frozen until the process exits.In every case the
completednotification did reach the root session, so the wake-routing (not the completion detection) appears to be where delivery dies. Happy to provide session/agent IDs or run variations if useful.Adding a reproducible variant: nested background task inside a background subagent never wakes it — result stranded until an external message arrives
We hit what appears to be an aggravated variant of this issue (and of the race described in #39632), in an interactive session on v2.1.191 (macOS).
Setup
Observed
wake up — at which point TaskStop reported the task no longer existed (already completed and cleaned up).
notification delivery to the main session works; it's the idle background subagent that never gets woken.
Impact
Any orchestration pattern of the form "background teammate babysits a long-running script and reports back" silently fails: the work completes, but the result never returns. In our run, 3 out of 4 spawned
teammates failed to proactively report results (this one being the worst case). That makes background subagents unreliable as autonomous workers for anything long-running.