charmbracelet/crush · error
error listing directory: %w
Error message
error listing directory: %w
What it means
After the existence check, ListDirectoryTree delegates to fsext.ListDirectory. Any walk/read error from that call is wrapped as 'error listing directory', preserving the underlying cause (permission denied, symlink loops, I/O errors).
Source
Thrown at internal/agent/tools/ls.go:152
},
)
}
func ListDirectoryTree(searchPath string, params LSParams, lsConfig config.ToolLs) (string, LSResponseMetadata, error) {
if _, err := os.Stat(searchPath); os.IsNotExist(err) {
return "", LSResponseMetadata{}, fmt.Errorf("path does not exist: %s", searchPath)
}
depth, limit := lsConfig.Limits()
maxFiles := cmp.Or(limit, maxLSFiles)
files, truncated, err := fsext.ListDirectory(
searchPath,
params.Ignore,
cmp.Or(params.Depth, depth),
maxFiles,
)
if err != nil {
return "", LSResponseMetadata{}, fmt.Errorf("error listing directory: %w", err)
}
metadata := LSResponseMetadata{
NumberOfFiles: len(files),
Truncated: truncated,
}
tree := createFileTree(files, searchPath)
var output string
if truncated {
output = fmt.Sprintf("There are more than %d files in the directory. Use a more specific path or use the Glob tool to find specific files. The first %[1]d files and directories are included below.\n", maxFiles)
}
if depth > 0 {
output = fmt.Sprintf("The directory tree is shown up to a depth of %d. Use a higher depth and a specific path to see more levels.\n", cmp.Or(params.Depth, depth))
}
return output + "\n" + printTree(tree, searchPath), metadata, nil
}
View on GitHub (pinned to 7944b8e522)
Solutions
- Inspect the wrapped %w error to find the root cause (permission vs I/O).
- Fix filesystem permissions on the target directory (chmod/chown) or run as an appropriate user.
- Confirm the path is a readable directory, not a special file.
- Retry if the failure was transient (e.g. network mount).
Example fix
// before
tree, _, _ := ListDirectoryTree("/root/secret", params, cfg)
// after
// chmod +rx the directory or choose a readable path first Defensive patterns
Strategy: try-catch
Validate before calling
if fi, err := os.Stat(searchPath); err == nil && !fi.IsDir() {
return errors.New("not a directory")
} Type guard
null
Try / catch
tree, meta, err := ListDirectoryTree(p, params, cfg)
if err != nil {
var perr *fs.PathError
if errors.As(err, &perr) { /* handle permission/I/O root cause */ }
} Prevention
- Ensure read/execute bits on directories being listed
- Watch for transient errors on network mounts and retry
- Check the wrapped error with errors.As for fs.PathError
When it happens
Trigger: Calling ListDirectoryTree on an existing path where fsext.ListDirectory fails, e.g. the process lacks read permission, the path is a file not a directory in edge cases, or the walker hits an unreadable subdirectory treated as fatal.
Common situations: Directories with restrictive modes (0700 owned by another user), encrypted/mounted volumes that return I/O errors, or sandboxed environments blocking traversal.
Related errors
- failed to create server working directory: %v
- create directory: %w
- failed to check if directory is empty: %w
- failed to create parent directories: %w
- failed to create output file: %w
AI-assisted analysis of charmbracelet/crush@7944b8e522 (2026-08-29).
Data as JSON: /api/errors/afb6b38aabd62851.
Report an issue: GitHub.