Hmbown/CodeWhale · error · anyhow::Error

Refusing on self (agent_id ' '); child coordination…

Error message

Refusing {action} on self (agent_id '{agent_id}'); child coordination authority is limited to strict descendants.

What it means

Subagent coordination authority is limited to strict descendants: an agent is never allowed to control itself. When the resolved caller identity equals the target agent's continuation identity, the operation (e.g. interrupt, terminate, send-a-command) is refused with this error.

Solutions

  1. Address the command at a child agent_id instead of the calling agent itself
  2. Skip the control call when target == caller in your tool-invocation logic
  3. Check the target id against the caller's own id before dispatching

Example fix

// before
control_agent(&caller_id, Action::Interrupt); // Err: refusing action on self
// after
if target_id != caller_id { control_agent(&target_id, Action::Interrupt); }
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_not_self(caller_id: &str, target_id: &str, action: &str) -> Result<(), String> {
    if caller_id == target_id { Err(format!("refusing {action} on self")) } else { Ok(()) }
}

Type guard

fn is_self_action(caller_id: &str, target_id: &str) -> bool {
    caller_id == target_id
}

Try / catch

match control_agent(target_id, action) {
    Err(e) if e.to_string().contains("Refusing") && e.to_string().contains("on self") => Ok(()), // no-op: acting on self is expected to be refused
    Err(e) => return Err(e),
    Ok(r) => Ok(r),
}

Prevention

When it happens

Trigger: A tool invocation where the caller and target agent_id resolve to the same continuation target — typically an agent issuing a control command addressed to itself, directly or via a self-referencing name.

Common situations: An LLM subagent mistakenly addressing its own name/id in an agent control tool call; loops where an agent retries an operation against itself after a partial failure.

Understand the failure class

Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at crates/tui/src/tools/subagent/mod.rs:7563

    ) -> Result<String> {
        let agent_id = self.resolve_agent_ref(agent_ref)?;
        let Some(caller) = caller_agent_id
            .map(str::trim)
            .filter(|caller| !caller.is_empty() && *caller != "root")
        else {
            return Ok(agent_id);
        };
        let caller_identity = if self.agents.contains_key(caller) {
            self.continuation_target(caller)?
        } else {
            // Internal headless parents can own a worker record without a
            // paired SubAgent projection. A missing caller still fails closed.
            self.worker_record_by_ref(caller)
                .map(|(id, _)| id)
                .ok_or_else(|| anyhow!("Calling agent not found"))?
        };
        if caller_identity == self.continuation_target(&agent_id)? {
            return Err(anyhow!(
                "Refusing {action} on self (agent_id '{agent_id}'); child coordination authority is limited to strict descendants."
            ));
        }

        let mut cursor = agent_id.clone();
        let mut visited = std::collections::HashSet::new();
        while visited.insert(cursor.clone()) {
            let Some((_, record)) = self.worker_record_by_ref(&cursor) else {
                break;
            };
            let Some(parent_ref) = record
                .parent_run_id
                .as_deref()
                .or(record.spec.parent_run_id.as_deref())
            else {
                break;
            };
            if parent_ref == "root" {

View on GitHub (pinned to 73e0f67d83)