Bug report
Environment
- OpenClaw 2026.6.5 (5181e4f), npm install, stable channel
- Gateway: systemd user service, local loopback, WSL2 (
linux 6.6.114.1-microsoft-standard-WSL2, node 22.22.0)
- Channel: WhatsApp (Baileys plugin 2026.6.5)
- Agents:
main (user-facing, pi runtime) → spawns workflow-lead (depth 1) → spawns content-lead / editorial-review (depth 2)
Summary
When a depth-1 subagent calls sessions_yield while waiting on its own depth-2 children, the background task that tracks that subagent run is settled as cancelled, and the standard cancellation notice — Background task cancelled: Subagent task (run <id>) — is delivered into the requester (user-facing) session as a visible message.
Nothing was actually cancelled: no operator ran openclaw tasks cancel, the requester agent made no cancel tool call, and the yielded subagent session kept orchestrating normally — it was woken by each child completion, ran all 5 planned steps, and produced the final deliverable ~37 minutes later.
Two problems:
- Status taxonomy violation. The docs (Background tasks) define
cancelled as "Stopped by the operator via openclaw tasks cancel". The yield path reuses this terminal status for a run that is, per the sub-agents doc, merely waiting ("the waiting primitive ... ends the current model turn and waits for runtime events").
- False-failure notice leaks to the end user. The cancellation notice is injected into the owner session and dispatched to the user channel (WhatsApp). The end user sees "Background task cancelled" for a job that is alive and ultimately succeeds. The requester agent then burns turns investigating (
subagents list shows the child as active (waiting on N children) — directly contradicting the notice).
Reproduction (observed twice, deterministic)
Flow: user asks main for a multi-step deliverable → main does sessions_spawn(agentId=workflow-lead) → workflow-lead spawns its first child and calls sessions_yield.
Occurrence 1 — run 78c48230:
| UTC time |
Event |
| 02:54:49 |
main spawn accepted → run 78c48230, child agent:workflow-lead:subagent:9a142fdd… |
| 02:55:07 |
workflow-lead spawns its own child (depth 2) |
| 02:55:10 |
workflow-lead calls sessions_yield → result {"status": "yielded"} |
| 02:55:10 |
Task for run 78c48230 settles cancelled (same second); notice delivered to main, dispatched to WhatsApp |
Occurrence 2 — run a07e4c37 (retry of the same job):
| UTC time |
Event |
| 03:00:38 |
main spawn accepted → run a07e4c37, child agent:workflow-lead:subagent:df8b8587… |
| 03:00:17 |
workflow-lead spawns step-1 child (depth 2) |
| 03:00:19 |
workflow-lead calls sessions_yield → {"status": "yielded"} |
| 03:00:40 |
Task for run a07e4c37 settles cancelled, with startedAt == endedAt == 1781233240686 (zero-duration run record); notice delivered to main, dispatched to WhatsApp |
| 03:03 → 03:38 |
The "cancelled" workflow-lead session keeps orchestrating: 5 spawn+yield cycles, all children succeed, final deliverable produced and announced at 03:38 |
Evidence
Task ledger (openclaw tasks list --json, trimmed/redacted):
{
"taskId": "883da0ed-ec58-4bcb-ba02-ce901d2cad8f",
"runtime": "subagent",
"requesterSessionKey": "agent:main:whatsapp:direct:+55XXXXXXXXXXX",
"ownerKey": "agent:main:whatsapp:direct:+55XXXXXXXXXXX",
"childSessionKey": "agent:workflow-lead:subagent:df8b8587-3b37-4a7d-8dd7-299862a77eb8",
"agentId": "main",
"runId": "a07e4c37-2815-44e2-928c-425f9b535e01",
"status": "cancelled",
"deliveryStatus": "delivered",
"createdAt": 1781233203657,
"startedAt": 1781233240686,
"endedAt": 1781233240686,
"lastEventAt": 1781233240686
}
workflow-lead session transcript (the yield that coincides with the settle):
{"timestamp":"...T03:00:19...","message":{"role":"assistant","content":[{"type":"toolCall","name":"sessions_yield","arguments":{"message":"Aguardando retorno do step_1."}}]}}
{"timestamp":"...T03:00:19...","message":{"role":"toolResult","content":[{"type":"text","text":"{\n \"status\": \"yielded\",\n \"message\": \"Aguardando retorno do step_1.\"\n}"}]}}
Requester (main) session — the notice arrives as a visible assistant message and goes out to the user channel:
{"timestamp":"...T03:00:20...","message":{"role":"assistant","content":[{"type":"text","text":"Background task cancelled: Subagent task (run a07e4c37)."}]}}
Same-session contradiction ~3 minutes later: subagents list from main reports the run's child session as active, "waiting on 2 children" — while the task ledger says cancelled.
The orchestration itself was healthy throughout: each depth-2 completion woke the yielded workflow-lead, which advanced its plan (update_plan) and spawned the next step, ending with the deliverable. So the cancelled settle is purely a bookkeeping/notification defect on the yield path — but it is user-visible and reads as a hard failure.
Expected behavior
- A subagent run that yields while waiting on children keeps its background task in a non-terminal state (
running, or a dedicated waiting state), OR settles it with a status that does not collide with operator cancellation semantics.
- No
Background task cancelled notice is delivered to the requester/user session unless the run was actually cancelled (operator tasks cancel, or an explicit cancel tool call).
Actual behavior
- First
sessions_yield of the depth-1 subagent → its tracking task settles cancelled (occurrence 1: same second as the yield; occurrence 2: 21 s later, with startedAt == endedAt).
- The cancellation notice is dispatched to the end user, who sees a false failure for a job that completes successfully minutes later.
Related (not duplicates)
These suggest the yield path settles/aborts the surrounding run in several contexts; this report adds the user-triggered subagent-chain case where the status lands as cancelled and the notice reaches the end user.
Bug report
Environment
linux 6.6.114.1-microsoft-standard-WSL2, node 22.22.0)main(user-facing, pi runtime) → spawnsworkflow-lead(depth 1) → spawnscontent-lead/editorial-review(depth 2)Summary
When a depth-1 subagent calls
sessions_yieldwhile waiting on its own depth-2 children, the background task that tracks that subagent run is settled ascancelled, and the standard cancellation notice —Background task cancelled: Subagent task (run <id>)— is delivered into the requester (user-facing) session as a visible message.Nothing was actually cancelled: no operator ran
openclaw tasks cancel, the requester agent made no cancel tool call, and the yielded subagent session kept orchestrating normally — it was woken by each child completion, ran all 5 planned steps, and produced the final deliverable ~37 minutes later.Two problems:
cancelledas "Stopped by the operator viaopenclaw tasks cancel". The yield path reuses this terminal status for a run that is, per the sub-agents doc, merely waiting ("the waiting primitive ... ends the current model turn and waits for runtime events").subagents listshows the child asactive (waiting on N children)— directly contradicting the notice).Reproduction (observed twice, deterministic)
Flow: user asks
mainfor a multi-step deliverable →maindoessessions_spawn(agentId=workflow-lead)→workflow-leadspawns its first child and callssessions_yield.Occurrence 1 — run
78c48230:mainspawn accepted → run78c48230, childagent:workflow-lead:subagent:9a142fdd…workflow-leadspawns its own child (depth 2)workflow-leadcallssessions_yield→ result{"status": "yielded"}78c48230settlescancelled(same second); notice delivered tomain, dispatched to WhatsAppOccurrence 2 — run
a07e4c37(retry of the same job):mainspawn accepted → runa07e4c37, childagent:workflow-lead:subagent:df8b8587…workflow-leadspawns step-1 child (depth 2)workflow-leadcallssessions_yield→{"status": "yielded"}a07e4c37settlescancelled, withstartedAt == endedAt == 1781233240686(zero-duration run record); notice delivered tomain, dispatched to WhatsAppworkflow-leadsession keeps orchestrating: 5 spawn+yield cycles, all children succeed, final deliverable produced and announced at 03:38Evidence
Task ledger (
openclaw tasks list --json, trimmed/redacted):{ "taskId": "883da0ed-ec58-4bcb-ba02-ce901d2cad8f", "runtime": "subagent", "requesterSessionKey": "agent:main:whatsapp:direct:+55XXXXXXXXXXX", "ownerKey": "agent:main:whatsapp:direct:+55XXXXXXXXXXX", "childSessionKey": "agent:workflow-lead:subagent:df8b8587-3b37-4a7d-8dd7-299862a77eb8", "agentId": "main", "runId": "a07e4c37-2815-44e2-928c-425f9b535e01", "status": "cancelled", "deliveryStatus": "delivered", "createdAt": 1781233203657, "startedAt": 1781233240686, "endedAt": 1781233240686, "lastEventAt": 1781233240686 }workflow-leadsession transcript (the yield that coincides with the settle):{"timestamp":"...T03:00:19...","message":{"role":"assistant","content":[{"type":"toolCall","name":"sessions_yield","arguments":{"message":"Aguardando retorno do step_1."}}]}} {"timestamp":"...T03:00:19...","message":{"role":"toolResult","content":[{"type":"text","text":"{\n \"status\": \"yielded\",\n \"message\": \"Aguardando retorno do step_1.\"\n}"}]}}Requester (
main) session — the notice arrives as a visible assistant message and goes out to the user channel:{"timestamp":"...T03:00:20...","message":{"role":"assistant","content":[{"type":"text","text":"Background task cancelled: Subagent task (run a07e4c37)."}]}}Same-session contradiction ~3 minutes later:
subagents listfrommainreports the run's child session asactive, "waiting on 2 children" — while the task ledger sayscancelled.The orchestration itself was healthy throughout: each depth-2 completion woke the yielded
workflow-lead, which advanced its plan (update_plan) and spawned the next step, ending with the deliverable. So thecancelledsettle is purely a bookkeeping/notification defect on the yield path — but it is user-visible and reads as a hard failure.Expected behavior
running, or a dedicatedwaitingstate), OR settles it with a status that does not collide with operator cancellation semantics.Background task cancellednotice is delivered to the requester/user session unless the run was actually cancelled (operatortasks cancel, or an explicit cancel tool call).Actual behavior
sessions_yieldof the depth-1 subagent → its tracking task settlescancelled(occurrence 1: same second as the yield; occurrence 2: 21 s later, withstartedAt == endedAt).Related (not duplicates)
sessions_yieldterminates isolated cron sessions instead of waiting (different surface; here the session survives, only the task record + notice are wrong)sessions_yieldThese suggest the yield path settles/aborts the surrounding run in several contexts; this report adds the user-triggered subagent-chain case where the status lands as
cancelledand the notice reaches the end user.