Hmbown/CodeWhale · error
Refusing {action} on self (agent_id '{agent_id}'); child coo
Error message
Refusing {action} on self (agent_id '{agent_id}'); child coordination authority is limited to strict descendants. What it means
Thrown by the sub-agent manager's coordination guard `ensure_caller_controls_descendant` (crates/tui/src/tools/subagent/mod.rs:6769) when a child agent attempts a control action (stop, pause, status, etc.) on itself. A child's coordination authority is deliberately limited to strict descendants; the guard first resolves the target ref, then refuses when the resolved agent_id equals the non-root caller id. Root callers (None, empty, or "root") bypass this check entirely, so it only fires for child-agent callers.
Source
Thrown at crates/tui/src/tools/subagent/mod.rs:6783
/// descendant of the calling agent. Root registries carry no caller id
/// (or the literal `root`) and retain authority over every child. This
/// prevents a child from messaging, waking, or interrupting a sibling or
/// ancestor and then claiming the ownership that target released.
pub(super) fn ensure_caller_controls_descendant(
&self,
agent_ref: &str,
caller_agent_id: Option<&str>,
action: &str,
) -> 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);
};
if caller == 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 == caller {View on GitHub (pinned to 0c42157ee5)
Solutions
- Filter the caller's own agent_id out of any enumerated agent list before issuing control actions.
- If the action genuinely must apply to that agent, issue it from the root session (caller None/"root"), where the guard passes.
- Target only refs of agents this child spawned, or spawn the target under this child first so it is a strict descendant.
- For self-termination, use the child's normal completion path (final report / finish) instead of a control action.
Example fix
// before (inside a child agent, caller_agent_id = Some(child_id))
manager.ensure_caller_controls_descendant("self", caller_agent_id, "stop")?; // Err 1200
// after
let target = manager.resolve_agent_ref(agent_ref)?;
if caller_agent_id == Some(target.as_str()) { return Ok(()); } // skip self
manager.ensure_caller_controls_descendant(&target, caller_agent_id, "stop")?; Defensive patterns
Strategy: validation
Validate before calling
fn is_self_target(resolved: &str, caller: Option<&str>) -> bool {
caller
.map(str::trim)
.is_some_and(|c| !c.is_empty() && c != "root" && c == resolved)
}
// before calling: if is_self_target(&manager.resolve_agent_ref(ref)?, caller) { skip } Type guard
fn safe_control_target(resolved: &str, caller: Option<&str>) -> bool {
match caller.map(str::trim) {
Some(c) if !c.is_empty() && c != "root" => c != resolved, // not self
_ => true, // root caller: guard bypassed
}
} Try / catch
match manager.ensure_caller_controls_descendant(&agent_ref, caller, action) {
Err(e) if e.to_string().contains("on self") => { /* skip self-targeted action, not fatal */ }
other => other?,
} Prevention
- Never pass self-referencing aliases ("self", "me") from child prompts.
- Filter the caller's own id out of any enumerated agent list before acting.
- Route cross-branch or fleet-wide control through the root session.
When it happens
Trigger: A sub-agent whose caller_agent_id is a non-empty, non-"root" id calls a control API with an agent_ref that `resolve_agent_ref` maps to the caller's own agent_id — e.g. passing "self", "me", an alias, or the literal id equal to the caller.
Common situations: Orchestrator prompts like "manage all your workers" where the child enumerates agents including itself; agent_ref aliases that resolve back to the caller; root-session commands copied into a child prompt and replayed verbatim.
Related errors
- Refusing {action} from agent '{caller}' to '{agent_id}'; a c
- fleet authority fingerprint `{expected}` is not a form this
- fleet authority mismatch at the spawn boundary: the receipt
- Codewhale-owned credential file {} exceeds the {} byte safet
- fleet run {} is already terminal ({lifecycle:?})
AI-assisted analysis of Hmbown/CodeWhale@0c42157ee5 (2026-08-20).
Data as JSON: /api/errors/4e01747e9ed7751e.
Report an issue: GitHub.