Skip to content

[Bug]: sessions_yield in a depth-1 subagent settles its background task as "cancelled" (operator-reserved status) and delivers a false "Background task cancelled" notice to the requester session #92448

Description

@aleps001

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:

  1. 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").
  2. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions