Hmbown/CodeWhale · error · anyhow::Error
Tool not allowed for this sub-agent
Error message
Tool {name} not allowed for this sub-agent What it means
The sub-agent's dispatch layer enforces its tool allow-list and per-family action permissions: if `is_tool_allowed(name)` is false (no allow-list membership) or the tool's family action is not permitted, the call is rejected with this generic not-allowed error. It precedes the deeper posture checks (read-only/no-shell enforcement).
Solutions
- Add the tool name to the sub-agent's `allowed_tools` list in the spawn/receipt configuration.
- Check the fingerprint's allow/deny fields and regenerate the receipt including the needed tool.
- Verify the family action is permitted for this role, or use an allowed action variant.
- Check tool-name spelling against the catalog (name-keyed matching is exact).
Example fix
// before
spawn_agent("v1;...;allow=read,search;..."); // child then calls Write
// after
spawn_agent("v1;...;allow=read,search,write;..."); Defensive patterns
Strategy: validation
Validate before calling
const allowed = childConfig.allowedTools;
if (allowed && !allowed.includes(toolName)) {
throw new Error(`${toolName} not in child allow-list`);
} Type guard
const isAllowedForChild = (name) => !childConfig.allowedTools || childConfig.allowedTools.includes(name);
Try / catch
try { result = await callTool(name, input); } catch (e) { if (String(e) === `Tool ${name} not allowed for this sub-agent`) { throw new Error(`add '${name}' to the spawn allow-list or use an allowed tool`); } } Prevention
- Keep the spawn allow-list in sync with the tools the delegated task requires
- Regenerate fingerprints after changing allow/deny configuration
- Match tool names exactly as they appear in the catalog
When it happens
Trigger: A sub-agent calls a tool whose name is not in its `allowed_tools` list (when one is set), or invokes a permitted tool with an action the family gate does not allow (`family_action_allowed` false).
Common situations: The parent's spawn config omitted a tool from the child's allow-list; the child tries a tool the parent restricted via the fingerprint's allow/deny lists; a family-action alias doesn't match the allowed set.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- agent action=claim widens an enforced write scope, and the…
- read-only roles may revise their private working notes
- Refusing from agent ' ' to ' '; a child may control only…
- Refusing on self (agent_id ' '); child coordination…
- [role.posture.denied] Tool
AI-assisted analysis of Hmbown/CodeWhale@433685b202 (2026-09-15).
Data as JSON: /api/errors/0aa07dbe01b1e235.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tools/subagent/mod.rs:17522
return Err(anyhow!(
"agent action=claim widens an enforced write scope, and the Fleet role `{role}` has no write authority to widen. Use an `implement` or `general` role.",
role = self.agent_type.as_str()
));
}
let family_action_allowed = if !Self::ACTION_ALIASES
.iter()
.any(|(family, _, _)| *family == name)
{
true
} else if let Some(action) = action {
self.is_action_allowed(name, action)
} else {
self.allowed_tools
.as_ref()
.is_none_or(|list| list.iter().any(|allowed| allowed == name))
};
if !self.is_tool_allowed(name) || !family_action_allowed {
return Err(anyhow!("Tool {name} not allowed for this sub-agent"));
}
// #3217: authoritative per-role posture — read-only roles cannot mutate
// and non-`Full`-shell roles cannot run shell, regardless of whether
// the parent session is auto-approved. This closes the auto-approve
// bypass where a read-only child could quietly write or shell out.
if !self.posture_permits_tool(name, Some(&input)) {
if self.allows_bounded_readonly_bash(name) {
return Err(anyhow!(
"[shell.readonly.command] Tool {name} input did not match the bounded read-only shell grammar for Fleet role `{role}`. {guidance}",
role = self.agent_type.as_str(),
guidance = codewhale_execpolicy::command_safety::readonly_command_help()
));
}
return Err(anyhow!(
"[role.posture.denied] Tool {name} is not permitted for the read-only Fleet role `{role}`. Use an `implement` or `general` role (or `custom` with an explicit allowed_tools list) to mutate the workspace or run shell commands.",
role = self.agent_type.as_str()
));
}View on GitHub (pinned to 433685b202)