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

  1. Check the child's policy/allow-list so tool_search is admitted when the child needs deferred-tool discovery
  2. Retry with a tool that is in the child's current catalog (inspect the catalog shown to the model)
  3. 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

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


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 surface

View on GitHub (pinned to 73e0f67d83)