sinelaw/fresh · error
buffer.cannot_open_directory
Error message
buffer.cannot_open_directory
What it means
open_file_no_focus_inner uses filesystem.is_dir (after canonicalizing, so symlinks are resolved) and bails with a localized message when the target path is a directory, since directories cannot be opened as editable buffers.
Solutions
- Check path.is_dir() before calling the open API and handle directories separately (e.g. open a file listing).
- Pass a concrete file path inside the directory instead of the directory itself.
- Resolve symlinks and verify the target is a regular file before opening.
Example fix
// before
editor.open_file("/home/user/project")?; // a directory
// after
let p = Path::new("/home/user/project");
if p.is_dir() { editor.open_directory_listing(p)?; } else { editor.open_file(p)?; } Defensive patterns
Strategy: validation
Validate before calling
let canon = std::fs::canonicalize(path)?; if canon.is_dir() { open_listing(&canon)?; return Ok(()); } Type guard
fn is_openable_file(p: &Path) -> bool { std::fs::canonicalize(p).map(|c| c.is_file()).unwrap_or(false) } Try / catch
if let Err(e) = editor.open_file(path) { if e.to_string().contains("cannot_open_directory") { editor.open_directory_listing(path)?; } } Prevention
- Canonicalize paths and check is_dir before opening
- Resolve symlinks — the check runs post-canonicalize
- Never pass directory URIs from plugins/LSP to file-open APIs
When it happens
Trigger: Calling open_file_no_focus / open_file_no_focus_with_kind / open_file_for_preview with a path that canonicalizes to a directory (is_dir returns true).
Common situations: Passing a directory path to a 'open file' command; opening a symlink that points at a directory; LSP or plugin handing the editor a folder URI.
Related errors
- project path does not exist
- Failed to read
- Cannot resolve import
- Failed to read plugin
- Invalid path encoding
AI-assisted analysis of sinelaw/fresh@67894ca546 (2026-09-13).
Data as JSON: /api/errors/4860972002122e8a.
Report an issue: GitHub.
Appendix: source
Thrown at crates/fresh-editor/src/app/file_open_orchestrators.rs:1142
.canonicalize(parent)
.unwrap_or_else(|_| parent.to_path_buf())
};
if let Some(filename) = resolved_path.file_name() {
canonical_parent.join(filename)
} else {
resolved_path
}
} else {
resolved_path
}
};
let path = canonical_path.as_path();
// Check if the path is a directory (after following symlinks via canonicalize)
// Directories cannot be opened as files in the editor
// Use filesystem trait method to support remote files
if self.authority().filesystem.is_dir(path).unwrap_or(false) {
anyhow::bail!(t!("buffer.cannot_open_directory"));
}
// Check if file is already open - return existing buffer without switching
let already_open = self
.buffers
.iter()
.find(|(_, state)| state.buffer.file_path() == Some(path))
.map(|(id, _)| *id);
if let Some(id) = already_open {
return Ok(id);
}
// If the current buffer is empty and unmodified, replace it instead of creating a new one
// Note: Don't replace composite buffers (they appear empty but are special views).
// Suppressed when `allow_replace_empty` is false — see
// `open_file_for_preview` for the rationale.
let replace_current = allow_replace_empty && {View on GitHub (pinned to 67894ca546)