{"record":{"id":"8dbc861b277d0b99","repo":"Hmbown/CodeWhale","slug":"notfound-8dbc86","errorCode":"NotFound","errorMessage":"{} not found on PATH","messagePattern":"(.+?) not found on PATH","errorType":"exception","errorClass":"std::io::Error","httpStatus":null,"severity":"error","filePath":"crates/tui/src/dependencies.rs","lineNumber":328,"sourceCode":"    ///\n    /// Callers should chain `.args(...)`, `.current_dir(...)`, and then\n    /// call `.output()`, `.status()`, or `.spawn()`.\n    fn command() -> Option<Command> {\n        let spec = Self::resolve()?;\n        let (program, fixed_args) = split_interpreter_spec(&spec);\n        let mut cmd = Command::new(&program);\n        crate::utils::suppress_console_window(&mut cmd);\n        for arg in &fixed_args {\n            cmd.arg(arg);\n        }\n        Some(cmd)\n    }\n\n    /// Convenience: run the tool with arguments in a working directory\n    /// and return the captured output.\n    fn output(args: &[&str], cwd: &std::path::Path) -> std::io::Result<std::process::Output> {\n        let mut cmd = Self::command().ok_or_else(|| {\n            std::io::Error::new(\n                std::io::ErrorKind::NotFound,\n                format!(\"{} not found on PATH\", std::any::type_name::<Self>()),\n            )\n        })?;\n        cmd.args(args).current_dir(cwd).output()\n    }\n\n    /// Convenience: run the tool with arguments and return only the\n    /// exit status (discards stdout/stderr).\n    #[allow(dead_code)]\n    fn status(args: &[&str], cwd: &std::path::Path) -> std::io::Result<std::process::ExitStatus> {\n        let mut cmd = Self::command().ok_or_else(|| {\n            std::io::Error::new(\n                std::io::ErrorKind::NotFound,\n                format!(\"{} not found on PATH\", std::any::type_name::<Self>()),\n            )\n        })?;\n        cmd.args(args).current_dir(cwd).status()","sourceCodeStart":310,"sourceCodeEnd":346,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/0c42157ee52f9d55af2b506d71b46249910f77d3/crates/tui/src/dependencies.rs#L310-L346","documentation":"ExternalTool::output()/status() helpers convert a failed tool resolution into NotFound \"<type> not found on PATH\", where <type> is the full Rust type name from std::any::type_name (e.g. codewhale_tui::dependencies::Git — read the last segment as the tool name). Resolution probes each candidate binary with --version once per process and caches the result, so the error means the probe failed at launch, not merely that Command::spawn would fail.","triggerScenarios":"Calling ExternalTool::output/status for Git, Gh, python, node, etc. in a process where none of the tool's candidate binaries respond to --version: not installed, not on PATH, or installed but broken (probe fails and resolution returns None).","commonSituations":"Slim CI/container images without git/gh/python; PATH differing between the interactive shell and the launching process; a tool present but erroring on --version so the probe rejects it; stale per-process cache after installing the tool mid-session.","solutions":["Identify the tool from the type name at the end of the message (e.g. ...::dependencies::Gh -> gh) and install it","Verify from the codewhale process's environment, not just your login shell: run <tool> --version the same way codewhale is launched","Add the tool's bin directory to PATH and restart codewhale so the once-per-process resolution cache re-probes","For Python remember the candidate ladder (python3 / py -3): the probe requires a working --version"],"exampleFix":"// before\nlet out = Git::output(&[\"diff\", \"--stat\"], &repo)?; // NotFound: ...::dependencies::Git not found on PATH\n\n// after: gate the feature on availability\nif !Git::available() {\n    return Err(anyhow!(\"git is required; install it and restart codewhale\"));\n}\nlet out = Git::output(&[\"diff\", \"--stat\"], &repo)?;","handlingStrategy":"validation","validationCode":"if !Git::available() {\n    return Err(\"git not found: install git and ensure it is on PATH\".into());\n}\nlet out = Git::output(&[\"diff\", \"--stat\"], &repo)?;","typeGuard":"fn tool_ready<T: ExternalTool>() -> bool {\n    T::available()\n}","tryCatchPattern":"match Git::output(args, cwd) {\n    Err(e) if e.kind() == io::ErrorKind::NotFound => {\n        // decode the tool from the message's type name; show an install hint, do not retry\n    }\n    other => other?,\n}","preventionTips":["Gate features on Tool::available() at startup and disable them with a hint instead of failing mid-run","Ensure the tool's bin dir is on the PATH of the launching process, not just your shell","Remember resolution is probed once per process: restart after installing a tool"],"tags":["dependencies","path","cli","subprocess"],"backgroundTag":"missing-executable-on-path","analyzedSha":"0c42157ee52f9d55af2b506d71b46249910f77d3","analyzedAt":"2026-08-20T21:50:45.477Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}