Kuberwastaken/claurst · error · anyhow::Error
Cannot read ' ' for LSP
Error message
Cannot read '{}' for LSP: {} What it means
Thrown in `LspManager::open_file` when `tokio::fs::read_to_string(file_path)` fails while loading file content to send as a `textDocument/didOpen` notification. The raw IO error (NotFound, PermissionDenied, invalid UTF-8, etc.) is embedded in the message. The file must be readable as UTF-8 text to be opened on the LSP server.
Solutions
- Verify the path exists and is a regular file before calling open_file (std::path::Path::is_file).
- Check file permissions and that the process user can read it.
- Ensure the file is valid UTF-8; skip or convert non-UTF-8 files before LSP open.
- Refresh any cached/stale path against the current filesystem.
Example fix
// before: unconditional open
manager.open_file(path, root).await?;
// after: pre-check the file
let p = std::path::Path::new(path);
if p.is_file() {
manager.open_file(path, root).await?;
} Defensive patterns
Strategy: validation
Validate before calling
let p = std::path::Path::new(path);
if !p.is_file() { bail!("not a readable file: {path}"); }
// optional UTF-8 pre-check
std::fs::read(p).and_then(|b| String::from_utf8(b).map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "not UTF-8")))?; Type guard
fn openable(path: &str) -> bool {
std::path::Path::new(path).is_file()
} Try / catch
match manager.open_file(path, root).await {
Ok(()) => {},
Err(e) if e.to_string().starts_with("Cannot read") => {
tracing::warn!("skipping LSP open for unreadable file {path}: {e}");
}
Err(e) => return Err(e),
} Prevention
- Check path existence and type before LSP operations.
- Skip binary or non-UTF-8 files when collecting files for LSP.
- Re-resolve paths against the working directory; beware deleted/stale buffers.
When it happens
Trigger: open_file(file_path, root_dir) is called with a path that does not exist, was deleted, lacks read permission, is a directory, or contains invalid UTF-8 bytes.
Common situations: Stale buffer referencing a deleted file; opening binary or non-UTF-8 files; typo in path or wrong working directory; file locked by permissions (e.g. root-owned file, sandboxed environment).
Understand the failure class
Background: "failed to read file", EACCES, ENOENT and "could not read <path>" errors: when a program can't read a file from disk — this error's family across 49 libraries.
Related errors
- Failed to start LSP server
- LSP server stdin not available
- LSP server stdout not available
- LSP client already shut down
- LSP request ' ' timed out (server: )
AI-assisted analysis of Kuberwastaken/claurst@b0637c97ec (2026-09-10).
Data as JSON: /api/errors/41f05c6f6143b417.
Report an issue: GitHub.
Appendix: source
Thrown at src-rust/crates/core/src/lsp.rs:1068
&mut self,
file_path: &str,
root_dir: &Path,
) -> anyhow::Result<()> {
let uri = path_to_uri(file_path);
let server_name = match self.server_name_for_file(file_path) {
Some(n) => n.to_string(),
None => return Ok(()),
};
// Skip if already opened on this server
if self.opened_files.get(&uri).map(|s| s.as_str()) == Some(server_name.as_str()) {
return Ok(());
}
let content = match tokio::fs::read_to_string(file_path).await {
Ok(c) => c,
Err(e) => {
return Err(anyhow::anyhow!(
"Cannot read '{}' for LSP: {}",
file_path,
e
))
}
};
// Ensure the server is running first (borrows self mutably, so must
// finish before we borrow opened_files).
self.ensure_started(file_path, root_dir).await?;
if let Some(client) = self.clients.get_mut(&server_name) {
let lang = client.server_config.language_for_file(file_path);
client.open_document(&uri, &lang, &content).await?;
self.opened_files.insert(uri, server_name);
}
Ok(())
}
View on GitHub (pinned to b0637c97ec)