Hmbown/CodeWhale · warning

parent cancellation fan-in

Error message

parent cancellation fan-in

What it means

Test assertion `completion_rx.try_recv().expect("parent cancellation fan-in")` at `crates/tui/src/tools/subagent/tests.rs:6601`. The test expects that when a parent cancels a child agent, exactly one completion event is fanned into the completion channel. A panic here means no completion event was delivered at all (try_recv returned Empty/Disconnected) — the cancellation did not propagate to the completion fan-in path.

Solutions

  1. Replace try_recv with a bounded recv (with timeout) in a debug run to distinguish 'no event ever' from 'not yet delivered' (race).
  2. Trace the cancel_agent path and confirm it sends an AgentComplete with cancelled status into the completion channel exactly once.
  3. Check the parent-child cancellation token wiring: interrupt/cancel must trigger the agent's terminal transition that emits the event.
  4. If a dedup/fan-in guard was added recently, ensure it drops duplicates, not the first event.

Example fix

// before
let completion = completion_rx.try_recv().expect("parent cancellation fan-in");
// after
let completion = tokio::time::timeout(std::time::Duration::from_secs(5), completion_rx.recv())
    .await
    .expect("timed out waiting for parent cancellation fan-in")
    .expect("completion channel closed before fan-in event");
Defensive patterns

Strategy: try-catch

Validate before calling

// Replace bare try_recv with a bounded await in tests:
let completion = tokio::time::timeout(Duration::from_secs(5), completion_rx.recv()).await;
assert!(matches!(completion, Ok(Some(_))), "expected exactly one fan-in completion");

Try / catch

let completion = timeout(Duration::from_secs(5), completion_rx.recv()).await
    .expect("fan-in event never arrived (timeout)")
    .expect("completion sender dropped before fan-in");

Prevention

When it happens

Trigger: The cancel path never emits the AgentComplete event: e.g. the cancellation token is not observed by the agent's wait loop, the completion sender was dropped before the cancel, or a refactor routes completion through a different channel/mailbox than the one this test drains.

Common situations: Changes to SubAgentManager's cancellation plumbing (token wiring, mailbox draining, fan-in dedup) that drop the terminal completion event; tests flaking if cancellation races event delivery — though try_recv after awaits should be deterministic if fan-in happens before return.

Related errors


AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22). Data as JSON: /api/errors/1eb53d648f663465. Report an issue: GitHub.

Appendix: source

Thrown at crates/tui/src/tools/subagent/tests.rs:6601

        Some(1),
        None,
    );

    let first = manager.cancel_agent(&agent_id).expect("first Stop");
    let second = manager.cancel_agent(&agent_id).expect("repeated Stop");
    assert_eq!(first.status, SubAgentStatus::Cancelled);
    assert_eq!(second.status, SubAgentStatus::Cancelled);
    assert_eq!(
        first
            .checkpoint
            .as_ref()
            .map(|checkpoint| checkpoint.reason.as_str()),
        Some("test_checkpoint")
    );

    let completion = completion_rx
        .try_recv()
        .expect("parent cancellation fan-in");
    assert!(completion.payload.contains(r#""status":"cancelled""#));
    assert!(completion_rx.try_recv().is_err());

    let terminal_mail = mailbox_rx
        .drain()
        .into_iter()
        .filter(|envelope| {
            matches!(
                envelope.message,
                MailboxMessage::Completed { .. }
                    | MailboxMessage::Failed { .. }
                    | MailboxMessage::Interrupted { .. }
                    | MailboxMessage::Cancelled { .. }
            )
        })
        .collect::<Vec<_>>();
    assert_eq!(terminal_mail.len(), 1);
    assert!(matches!(

View on GitHub (pinned to 73e0f67d83)