zed-industries/zed · error

{input_path} is not a directory.

Error message

{input_path} is not a directory.

What it means

The path exists in the worktree snapshot but is a file, not a directory: `entry.is_dir()` is false. The list-directory tool only enumerates directories, so the call fails with this message naming the input path. Nothing is listed and no filesystem access happens beyond the lookup.

Source

Thrown at crates/agent/src/tools/list_directory_tool.rs:131

        input_path: &str,
        cx: &App,
    ) -> Result<String> {
        let worktree = project
            .read(cx)
            .worktree_for_id(project_path.worktree_id, cx)
            .with_context(|| format!("{input_path} is not in a known worktree"))?;

        let global_settings = WorktreeSettings::get_global(cx);
        let worktree_settings = WorktreeSettings::get(Some(project_path.into()), cx);
        let worktree_snapshot = worktree.read(cx).snapshot();
        let worktree_root_name = worktree.read(cx).root_name();

        let Some(entry) = worktree_snapshot.entry_for_path(&project_path.path) else {
            return Err(anyhow!("Path not found: {}", input_path));
        };

        if !entry.is_dir() {
            return Err(anyhow!("{input_path} is not a directory."));
        }

        let mut folders = Vec::new();
        let mut files = Vec::new();

        for entry in worktree_snapshot.child_entries(&project_path.path) {
            // Skip private and excluded files and directories
            if global_settings.is_path_private(&entry.path)
                || global_settings.is_path_excluded(&entry.path)
            {
                continue;
            }

            let project_path: ProjectPath = (worktree_snapshot.id(), entry.path.clone()).into();
            if worktree_settings.is_path_excluded(&project_path.path)
                || worktree_settings.is_path_private(&project_path.path)
            {
                continue;

View on GitHub (pinned to bc538def45)

Solutions

  1. Pass the parent directory instead: `src/main.rs` → `src`.
  2. Use the read-file tool when the target is a file.
  3. Strip trailing file components from model-provided paths before invoking the tool.

Example fix

# before
list_directory("Cargo.toml")   # '<input> is not a directory.'

# after
list_directory(".")            # or: read_file("Cargo.toml")
Defensive patterns

Strategy: validation

Validate before calling

let Some(entry) = worktree_snapshot.entry_for_path(&project_path.path) else {
    anyhow::bail!("path not found: {input_path}");
};
if !entry.is_dir() {
    anyhow::bail!("{input_path} is a file — pass its parent directory");
}

Type guard

fn is_directory_in_worktree(
    snapshot: &WorktreeSnapshot,
    project_path: &ProjectPath,
) -> bool {
    snapshot
        .entry_for_path(&project_path.path)
        .map(|entry| entry.is_dir())
        .unwrap_or(false)
}

Prevention

When it happens

Trigger: Passing a file path (e.g. `Cargo.toml`, `src/main.rs`) to the list-directory tool instead of a directory.

Common situations: The model confusing the list-directory and read-file tools; paths whose final component is a file (`src/lib.rs` instead of `src`); trailing-component mistakes after path manipulation.

Related errors


AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16). Data as JSON: /api/errors/acbb4a1522dda373. Report an issue: GitHub.