{"record":{"id":"4e01747e9ed7751e","repo":"Hmbown/CodeWhale","slug":"refusing-action-on-self-agent-id-agent-id","errorCode":null,"errorMessage":"Refusing {action} on self (agent_id '{agent_id}'); child coordination authority is limited to strict descendants.","messagePattern":"Refusing (.+?) on self \\(agent_id '(.+?)'\\); child coordination authority is limited to strict descendants\\.","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/subagent/mod.rs","lineNumber":7563,"sourceCode":"    ) -> Result<String> {\n        let agent_id = self.resolve_agent_ref(agent_ref)?;\n        let Some(caller) = caller_agent_id\n            .map(str::trim)\n            .filter(|caller| !caller.is_empty() && *caller != \"root\")\n        else {\n            return Ok(agent_id);\n        };\n        let caller_identity = if self.agents.contains_key(caller) {\n            self.continuation_target(caller)?\n        } else {\n            // Internal headless parents can own a worker record without a\n            // paired SubAgent projection. A missing caller still fails closed.\n            self.worker_record_by_ref(caller)\n                .map(|(id, _)| id)\n                .ok_or_else(|| anyhow!(\"Calling agent not found\"))?\n        };\n        if caller_identity == self.continuation_target(&agent_id)? {\n            return Err(anyhow!(\n                \"Refusing {action} on self (agent_id '{agent_id}'); child coordination authority is limited to strict descendants.\"\n            ));\n        }\n\n        let mut cursor = agent_id.clone();\n        let mut visited = std::collections::HashSet::new();\n        while visited.insert(cursor.clone()) {\n            let Some((_, record)) = self.worker_record_by_ref(&cursor) else {\n                break;\n            };\n            let Some(parent_ref) = record\n                .parent_run_id\n                .as_deref()\n                .or(record.spec.parent_run_id.as_deref())\n            else {\n                break;\n            };\n            if parent_ref == \"root\" {","sourceCodeStart":7545,"sourceCodeEnd":7581,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tools/subagent/mod.rs#L7545-L7581","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Address the command at a child agent_id instead of the calling agent itself","Skip the control call when target == caller in your tool-invocation logic","Check the target id against the caller's own id before dispatching"],"exampleFix":"// before\ncontrol_agent(&caller_id, Action::Interrupt); // Err: refusing action on self\n// after\nif target_id != caller_id { control_agent(&target_id, Action::Interrupt); }","handlingStrategy":"validation","validationCode":"fn ensure_not_self(caller_id: &str, target_id: &str, action: &str) -> Result<(), String> {\n    if caller_id == target_id { Err(format!(\"refusing {action} on self\")) } else { Ok(()) }\n}","typeGuard":"fn is_self_action(caller_id: &str, target_id: &str) -> bool {\n    caller_id == target_id\n}","tryCatchPattern":"match control_agent(target_id, action) {\n    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\n    Err(e) => return Err(e),\n    Ok(r) => Ok(r),\n}","preventionTips":["Compare target agent_id against the caller's own id before dispatching any control command","Have the LLM prompt/tool schema reject self-addressed targets early","Log agent_id at spawn so prompts always reference the correct child ids"],"tags":["subagent","rust","permissions"],"backgroundTag":"insufficient-permissions","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}