nikivdev/code · error

external CLI tool {} not found under {}

Error message

external CLI tool {} not found under {}

What it means

`resolve_external_cli_tool_in_roots` searches the configured root directories for a manifest matching the requested tool id. When zero manifests match, it bails with this error listing all the root paths that were searched.

Source

Thrown at src/external_cli.rs:375

) -> Result<ResolvedExternalCliTool> {
    let mut matches = Vec::new();

    for root in roots {
        for candidate in candidate_manifest_paths(root) {
            let manifest = read_manifest(&candidate)?;
            if manifest.id == id {
                matches.push(resolved_from_manifest(
                    candidate,
                    manifest,
                    ExternalCliResolutionKind::DevRoot,
                    None,
                )?);
            }
        }
    }

    match matches.len() {
        0 => bail!(
            "external CLI tool {} not found under {}",
            id,
            roots
                .iter()
                .map(|path| path.display().to_string())
                .collect::<Vec<_>>()
                .join(", ")
        ),
        1 => Ok(matches.remove(0)),
        _ => {
            let locations = matches
                .iter()
                .map(|tool| tool.manifest_path.display().to_string())
                .collect::<Vec<_>>()
                .join(", ");
            bail!(
                "multiple external CLI manifests matched {}: {}",
                id,

View on GitHub (pinned to a747e741ae)

Solutions

  1. Check the tool id spelling against the manifest's `id` field.
  2. List the roots shown in the message and confirm the manifest exists under one of them with the expected filename (`MANIFEST_NAME`).
  3. Install or link the tool into one of the roots (e.g. via the install/link flow).
  4. Correct your roots configuration to include the directory containing the manifest.

Example fix

// before
let tool = resolver.resolve_external_cli_tool("my-clii", &roots)?;
// after
let tool = resolver.resolve_external_cli_tool("my-cli", &roots)?;
Defensive patterns

Strategy: validation

Validate before calling

fn assert_tool_installed(id: &str, roots: &[PathBuf]) -> Result<(), String> {
    for root in roots {
        let found = walk_manifests(root)?.any(|m| m.id == id);
        if found { return Ok(()); }
    }
    Err(format!("tool {id} not present under any of {:?}", roots))
}

Try / catch

match resolver.resolve_external_cli_tool(id, &roots) {
    Err(e) if e.to_string().contains("not found under") => {
        eprintln!("installing missing tool {id}...");
        installer.install(id)?;
        resolver.resolve_external_cli_tool(id, &roots)
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling `resolve_external_cli_tool(id, roots)` (or `resolves_manifest_from_roots`) where no manifest file under any root declares `id = "<requested id>"`.

Common situations: Typo in the tool id; tool never installed/linked into a root; manifest placed in the wrong directory or with the wrong filename; roots configured to a path that doesn't contain the tool.

Related errors


AI-assisted analysis of nikivdev/code@a747e741ae (2026-09-01). Data as JSON: /api/errors/e204dcaa1cbc137a. Report an issue: GitHub.