zed-industries/zed · error
Cannot list directory because its path matches the user's…
Error message
Cannot list directory because its path matches the user's worktree `private_paths` setting: {} What it means
Zed's agent `list_directory` tool refuses to enumerate a directory whose path matches the worktree-level `private_paths` setting. Private paths are a stronger restriction than scan exclusions: they exist purely to keep contents (even path names) away from the model, so listing is denied even though the files exist. It fires when `WorktreeSettings::get(...).is_path_private(&project_path.path)` returns true, after the worktree `file_scan_exclusions` check.
Solutions
- If access is genuinely required, remove the path from `private_paths` in the worktree `.zed/settings.json` — but prefer moving secrets out of the project instead.
- Keep the path private and instruct the agent/model to avoid it; retrying with a different phrasing will not bypass the check.
- Verify the path is not also matched by global `private_files` or `file_scan_exclusions`, since those checks run first and produce their own messages.
- Point the agent at a sanitized copy of the directory outside the matched pattern.
Example fix
// .zed/settings.json (worktree settings)
// before
{
"private_paths": ["secrets"]
}
// after — only the key material is private, the directory itself listable
{
"private_paths": ["secrets/*.key"]
} Defensive patterns
Strategy: validation
Validate before calling
let worktree = WorktreeSettings::get(Some((&project_path).into()), cx);
if worktree.is_path_private(&project_path.path) {
// do not call list_directory on this path; it is private by policy
} Try / catch
match list_directory(path).await {
Err(e) if e.to_string().contains("private_paths") => {
// privacy boundary hit — stop, never retry with variations
}
rest => rest,
} Prevention
- Scope `private_paths` to specific secret files/dirs, not whole trees the agent may need to navigate.
- Treat these refusals as expected behavior in agent loop code; filter such paths out of planned tool calls.
- Keep secrets outside the worktree so exclusions and agent needs never collide.
When it happens
Trigger: The `list_directory` tool is called on a path matched by `private_paths` (or `private_files` glob patterns) in the project's `.zed/settings.json`, e.g. `.env`, `secrets/`, `*.pem`.
Common situations: Users add `.env`, SSH keys, or credential directories to `private_paths` to keep them out of agent context, then prompt the agent to inspect those directories. The error is the privacy boundary working as designed.
Related errors
- Cannot list directory because its path matches the user's…
- Cannot read file because its path matches the global…
- Cannot read file because its path matches the global…
- Cannot read file because its path matches the worktree…
- auto_compact threshold of 0 is not valid
AI-assisted analysis of zed-industries/zed@f4178619ac (2026-08-20).
Data as JSON: /api/errors/3aca45a7e6e3688d.
Report an issue: GitHub.
Appendix: source
Thrown at crates/agent/src/tools/list_directory_tool.rs:300
}
if global_settings.is_path_private(&project_path.path) {
anyhow::bail!(
"Cannot list directory because its path matches the user's global `private_files` setting: {}",
input.path
);
}
let worktree_settings = WorktreeSettings::get(Some((&project_path).into()), cx);
if worktree_settings.is_path_excluded(&project_path.path) {
anyhow::bail!(
"Cannot list directory because its path matches the user's worktree `file_scan_exclusions` setting: {}",
input.path
);
}
if worktree_settings.is_path_private(&project_path.path) {
anyhow::bail!(
"Cannot list directory because its path matches the user's worktree `private_paths` setting: {}",
input.path
);
}
let worktree_snapshot = worktree.read(cx).snapshot();
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!("{} is not a directory.", input.path);
}
anyhow::Ok(())
}).map_err(|e| e.to_string())?;
if let Some(canonical_target) = &symlink_canonical_target {
let authorize = cx.update(|cx| {View on GitHub (pinned to f4178619ac)