rust-lang/rust-analyzer · error
We explicitly do not provide canonicalization API, as that i
Error message
We explicitly do not provide canonicalization API, as that is almost always a wrong solution, see #14430
What it means
The `paths` crate intentionally does not expose a canonicalization API. `AbsPath::canonicalize` is declared with the never type `!` and unconditionally panics, steering developers away from canonicalization, which the maintainers consider almost always the wrong solution (see issue #14430, e.g. because it resolves symlinks and changes identity of paths in ways that break caching and correctness assumptions).
Source
Thrown at crates/paths/src/lib.rs:251
///
/// # Example
/// ```ignore
/// # use paths::AbsPathBuf;
/// let abs_path_buf = AbsPathBuf::assert("/a/../../b/.//c//".into());
/// let normalized = abs_path_buf.normalize();
/// assert_eq!(normalized, AbsPathBuf::assert("/b/c".into()));
/// ```
pub fn normalize(&self) -> AbsPathBuf {
AbsPathBuf(normalize_path(&self.0))
}
/// Equivalent of [`Utf8Path::to_path_buf`] for `AbsPath`.
pub fn to_path_buf(&self) -> AbsPathBuf {
AbsPathBuf::try_from(self.0.to_path_buf()).unwrap()
}
pub fn canonicalize(&self) -> ! {
panic!(
"We explicitly do not provide canonicalization API, as that is almost always a wrong solution, see #14430"
)
}
/// Equivalent of [`Utf8Path::strip_prefix`] for `AbsPath`.
///
/// Returns a relative path.
pub fn strip_prefix(&self, base: &AbsPath) -> Option<&RelPath> {
self.0.strip_prefix(base).ok().map(RelPath::new_unchecked)
}
pub fn starts_with(&self, base: &AbsPath) -> bool {
self.0.starts_with(&base.0)
}
pub fn ends_with(&self, suffix: &RelPath) -> bool {
self.0.ends_with(&suffix.0)
}
pub fn name_and_extension(&self) -> Option<(&str, Option<&str>)> {View on GitHub (pinned to e8f7e90aa3)
Solutions
- Do not canonicalize; use `AbsPath::normalize`-style logical normalization or `Path::absolutize`-like logic if you only need `..` removal
- Use `std::path::Path::canonicalize` on the underlying path directly if you truly need symlink resolution, then convert back via `AbsPathBuf::try_from`
- Reconsider the design: rust-analyzer deliberately avoids canonicalization because it breaks path identity expectations; model your problem without it
Example fix
// before
let canon = abs_path.canonicalize();
// after
let canon: std::io::Result<AbsPathBuf> =
std::fs::canonicalize(abs_path.as_ref()).and_then(|p| Ok(AbsPathBuf::try_from(p)?)); Defensive patterns
Strategy: validation
Validate before calling
fn safe_canonicalize(p: &AbsPath) -> std::io::Result<AbsPathBuf> {
std::fs::canonicalize(p.as_ref()).map(|q| AbsPathBuf::try_from(q).unwrap())
} Type guard
// AbsPath exposes no canonicalize; guard by feature-checking in your own code
fn supports_canonicalize() -> bool { false } Prevention
- Never call paths::AbsPath::canonicalize - it always panics
- Use std::fs::canonicalize on the raw path and convert back with AbsPathBuf::try_from
- Prefer logical normalization (removing ..) over filesystem canonicalization
- Read issue #14430 to understand why canonicalization is discouraged here
When it happens
Trigger: Calling `AbsPath::canonicalize()` (or `AbsPathBuf::canonicalize()`) anywhere in code that depends on the `paths` crate. The method always panics; there is no input that makes it succeed.
Common situations: Migrating code from `std::path::Path::canonicalize` or `camino` usage to rust-analyzer's `AbsPath` API; trying to normalize `..` components or resolve symlinks before passing paths to the analyzer.
Related errors
AI-assisted analysis of rust-lang/rust-analyzer@e8f7e90aa3 (2026-09-03).
Data as JSON: /api/errors/2652b78ddc76b546.
Report an issue: GitHub.