nikivdev/code · error

{} must be an external CLI source directory or {} file

Error message

{} must be an external CLI source directory or {} file

What it means

The fallthrough case of `resolve_install_source_paths`: the given path is neither a directory containing a manifest nor a file named `MANIFEST_NAME`. The library cannot interpret it as an external CLI source and bails.

Source

Thrown at src/external_cli.rs:458

    let meta = fs::metadata(path)
        .with_context(|| format!("failed to read external CLI source {}", path.display()))?;
    if meta.is_dir() {
        let manifest_path = path.join(MANIFEST_NAME);
        if !manifest_path.is_file() {
            bail!("{} does not contain {}", path.display(), MANIFEST_NAME);
        }
        return Ok((path.to_path_buf(), manifest_path));
    }

    if meta.is_file() && path.file_name().and_then(|name| name.to_str()) == Some(MANIFEST_NAME) {
        let source_root = path
            .parent()
            .unwrap_or_else(|| Path::new("."))
            .to_path_buf();
        return Ok((source_root, path.to_path_buf()));
    }

    bail!(
        "{} must be an external CLI source directory or {} file",
        path.display(),
        MANIFEST_NAME
    )
}

fn link_record_path(id: &str) -> PathBuf {
    link_records_dir().join(format!("{}.toml", id))
}

fn link_records_dir() -> PathBuf {
    config::global_config_dir().join("cli").join("links")
}

fn ensure_link_records_dir() -> Result<PathBuf> {
    let dir = link_records_dir();
    fs::create_dir_all(&dir).with_context(|| format!("failed to create {}", dir.display()))?;
    Ok(dir)

View on GitHub (pinned to a747e741ae)

Solutions

  1. Pass either the tool's source directory or the manifest file itself (named exactly `MANIFEST_NAME`).
  2. Fix typos in the path.
  3. Verify the path exists and check its type (`ls -la`).
  4. If installing from a file, rename it to the expected manifest name or pass its parent directory.

Example fix

// before
installer.install_external_cli_link(Path::new("~/src/my-tool/README.md"))?;
// after
installer.install_external_cli_link(Path::new("~/src/my-tool"))?;
Defensive patterns

Strategy: validation

Validate before calling

fn assert_path_is_source(path: &Path, manifest_name: &str) -> Result<(), String> {
    match std::fs::metadata(path) {
        Ok(m) if m.is_dir() && path.join(manifest_name).is_file() => Ok(()),
        Ok(m) if m.is_file() && path.file_name().map_or(false, |n| n == manifest_name) => Ok(()),
        _ => Err(format!("{} is not a tool dir or manifest file", path.display())),
    }
}

Try / catch

match installer.install_external_cli_link(&p) {
    Err(e) if e.to_string().contains("must be an external CLI source") => {
        eprintln!("{e}; check the path points at a tool directory or manifest");
        Err(e)
    }
    other => other,
}

Prevention

When it happens

Trigger: Calling `install_external_cli_link` with a path that is a regular file whose name is not `MANIFEST_NAME`, or a non-directory/non-file entry (device, socket, broken symlink).

Common situations: Passing a README or binary instead of the manifest; passing a path with a typo so it resolves to the wrong file type; pointing at an arbitrary file inside the tool directory instead of the tool directory itself.

Related errors


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