{"record":{"id":"936317f95b657c04","repo":"Hmbown/CodeWhale","slug":"sub-agent-requested-unavailable-tools","errorCode":null,"errorMessage":"Sub-agent requested unavailable tools: {}","messagePattern":"Sub-agent requested unavailable tools: (.+?)","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/tools/subagent/mod.rs","lineNumber":13049,"sourceCode":"        agent_type.clone(),\n        agent_id.clone(),\n        assignment\n            .role\n            .as_deref()\n            .filter(|role| !role.trim().is_empty())\n            .unwrap_or(agent_type.as_str())\n            .to_string(),\n        allowed_tools.clone(),\n        // This agent's own list, allocated by `child_runtime()` (#4810). It is\n        // writable by this agent alone: neither the parent nor a sibling holds\n        // this `Arc`, so `work_update` here cannot reach the parent's Work\n        // checklist or work graph.\n        runtime.todos.clone(),\n        Arc::new(Mutex::new(PlanState::default())),\n    );\n    let unavailable_tools = tool_registry.unavailable_allowed_tools();\n    if !unavailable_tools.is_empty() {\n        return Err(anyhow!(\n            \"Sub-agent requested unavailable tools: {}\",\n            unavailable_tools.join(\", \")\n        ));\n    }\n    let tool_catalog = tool_registry.deferred_catalog_for_model(&agent_type);\n    let mut tool_surface = SubAgentToolSurface::new(tool_catalog, &[]);\n    let mut steps = 0;\n    let mut final_result: Option<String> = None;\n    let mut pending_inputs: VecDeque<SubAgentInput> = VecDeque::new();\n    let mut latest_checkpoint: Option<SubAgentCheckpoint> = None;\n    let mut tokens_used: u64 = 0;\n    let mut terminal_failure_reason: Option<String> = None;\n    let mut budget_failure_reason: Option<String> = None;\n    let mut handback_note: Option<String> = None;\n    // Distinguish a real \"the model chose to stop\" exit from an explicitly\n    // configured step-cap exit. The normal loop is unbounded (max_steps == 0).\n    let mut stopped_naturally = false;\n    // #6015: every child worker runs the same typed-denial no-progress guard","sourceCodeStart":13031,"sourceCodeEnd":13067,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/tools/subagent/mod.rs#L13031-L13067","documentation":"When a sub-agent is constructed, the tool registry reports which allowed tools are unavailable in this environment (unavailable_allowed_tools). If any requested-but-unavailable tool exists, the child is refused at construction with this error listing them, instead of silently running with a missing tool surface. This is the fail-loud companion to 'misconfiguration fails loud'.","triggerScenarios":"Creating/launching a sub-agent whose tool configuration (allow-list, agent-type default tools) names tools that cannot be provided in the current environment or build — e.g. a tool gated behind a missing binary, disabled feature, or removed surface.","commonSituations":"Config written on a machine with extra tools installed being reused on a leaner environment; a deprecated/renamed tool still listed in an allow-list; a feature flag disabled for the child's runtime.","solutions":["Remove the unavailable tool names from the sub-agent's allow-list/agent config","Enable the feature or install the dependency that provides the named tool","Check tool renames between versions and update the config to the current tool names","Verify the environment (PATH, feature flags) the child inherits actually provides the requested tools"],"exampleFix":"// before: allow-list names a tool this build lacks\nallow = [\"read\", \"browser\"]   // browser unavailable here\n// after\nallow = [\"read\", \"search\"]   // tools present in this environment","handlingStrategy":"validation","validationCode":"let unavailable = registry.unavailable_allowed_tools();\nif !unavailable.is_empty() {\n    eprintln!(\"fix allow-list before spawn: {}\", unavailable.join(\", \"));\n    return Err(anyhow!(\"remove or enable: {}\", unavailable.join(\", \")));\n}","typeGuard":null,"tryCatchPattern":"match spawn_subagent(config) {\n    Err(e) if e.to_string().contains(\"requested unavailable tools\") => {\n        let fixed = strip_unavailable(config);\n        spawn_subagent(fixed)\n    }\n    other => other,\n}","preventionTips":["Validate tool allow-lists against the current environment before spawn","Remove deprecated tool names from configs when upgrading","Test sub-agent configs in CI on the same environment profile used in production"],"tags":["subagent","tools","configuration"],"backgroundTag":"missing-dependency","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"}