Hmbown/CodeWhale · error · anyhow::Error
Tool is not in this child's catalog
Error message
Tool {name} is not in this child's catalog What it means
The child's tool dispatch first checks request_active_names before executing; for the tool_search tool itself, if it is not in the active (admitted) name set for this request, the call is refused with this error. A child may only invoke tools actually present in its (policy-filtered, activation-gated) catalog for the current request — nothing is reachable by guessing names.
Solutions
- Check the child's policy/allow-list so tool_search is admitted when the child needs deferred-tool discovery
- Retry with a tool that is in the child's current catalog (inspect the catalog shown to the model)
- If the child does not need discovery, call the concrete tool directly instead of tool_search
Example fix
// before: calling tool_search when it is not active for the request
{"name": "tool_search", "input": {"query": "read file"}}
// after: use a tool actually in the child's catalog
{"name": "read", "input": {"path": "src/main.rs"}} Defensive patterns
Strategy: type-guard
Validate before calling
if !child.active_tool_names().contains("tool_search") {
return Err("tool_search not active for this request".into());
} Type guard
fn tool_is_active(child: &SubAgent, name: &str) -> bool {
child.request_active_names().contains(name)
} Try / catch
match child.call_tool(name, input) {
Err(e) if e.to_string().contains("not in this child's catalog") =>
Err(anyhow!("pick a tool from the child's visible catalog")),
other => other,
} Prevention
- Only call tools listed in the child's visible catalog for the current request
- Keep policy filters consistent so tool_search is admitted when discovery is needed
- Do not replay tool calls recorded against a different request's active set
When it happens
Trigger: A sub-agent (or model on its behalf) invoking tool_search when tool_search was not admitted into the request's active tool set — e.g. the parent's policy excluded it or it was never hydrated for this request.
Common situations: A model hallucinating/assuming tool_search is always available, a policy filter that stripped it from the child's catalog, or replaying a tool call recorded from a request where it was active.
Understand the failure class
Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.
Related errors
- Tool is not in this child's policy-filtered catalog
- Sub-agent requested unavailable tools
- Tool could not enter the bounded child toolbox; use…
- Tool not allowed for this sub-agent
- agent action=claim widens an enforced write scope, and the…
AI-assisted analysis of Hmbown/CodeWhale@73e0f67d83 (2026-09-22).
Data as JSON: /api/errors/50850122cd12f8ac.
Report an issue: GitHub.
Appendix: source
Thrown at crates/tui/src/tools/subagent/mod.rs:18116
#[cfg(test)]
async fn execute(&self, agent_id: &str, name: &str, input: Value) -> Result<String> {
self.execute_full(agent_id, "", name, input)
.await
.map(|result| result.result.content)
}
async fn execute_from_surface(
&self,
agent_id: &str,
tool_id: &str,
surface: &mut SubAgentToolSurface,
request_active_names: &std::collections::HashSet<String>,
name: &str,
input: Value,
) -> Result<RichToolResult> {
if is_tool_search_tool(name) {
if !request_active_names.contains(name) {
return Err(anyhow!("Tool {name} is not in this child's catalog"));
}
return surface
.search(name, &input)
.map(|content| RichToolResult::plain(ToolResult::success(content)));
}
let Some(deferred) = surface
.catalog
.iter()
.find(|tool| tool.name == name)
.map(|tool| tool.defer_loading.unwrap_or(false))
else {
return Err(anyhow!(
"Tool {name} is not in this child's policy-filtered catalog"
));
};
if deferred && !request_active_names.contains(name) {
return surfaceView on GitHub (pinned to 73e0f67d83)