{"record":{"id":"2652b78ddc76b546","repo":"rust-lang/rust-analyzer","slug":"we-explicitly-do-not-provide-canonicalization-api","errorCode":null,"errorMessage":"We explicitly do not provide canonicalization API, as that is almost always a wrong solution, see #14430","messagePattern":"We explicitly do not provide canonicalization API, as that is almost always a wrong solution, see #14430","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/paths/src/lib.rs","lineNumber":251,"sourceCode":"    ///\n    /// # Example\n    /// ```ignore\n    /// # use paths::AbsPathBuf;\n    /// let abs_path_buf = AbsPathBuf::assert(\"/a/../../b/.//c//\".into());\n    /// let normalized = abs_path_buf.normalize();\n    /// assert_eq!(normalized, AbsPathBuf::assert(\"/b/c\".into()));\n    /// ```\n    pub fn normalize(&self) -> AbsPathBuf {\n        AbsPathBuf(normalize_path(&self.0))\n    }\n\n    /// Equivalent of [`Utf8Path::to_path_buf`] for `AbsPath`.\n    pub fn to_path_buf(&self) -> AbsPathBuf {\n        AbsPathBuf::try_from(self.0.to_path_buf()).unwrap()\n    }\n\n    pub fn canonicalize(&self) -> ! {\n        panic!(\n            \"We explicitly do not provide canonicalization API, as that is almost always a wrong solution, see #14430\"\n        )\n    }\n\n    /// Equivalent of [`Utf8Path::strip_prefix`] for `AbsPath`.\n    ///\n    /// Returns a relative path.\n    pub fn strip_prefix(&self, base: &AbsPath) -> Option<&RelPath> {\n        self.0.strip_prefix(base).ok().map(RelPath::new_unchecked)\n    }\n    pub fn starts_with(&self, base: &AbsPath) -> bool {\n        self.0.starts_with(&base.0)\n    }\n    pub fn ends_with(&self, suffix: &RelPath) -> bool {\n        self.0.ends_with(&suffix.0)\n    }\n\n    pub fn name_and_extension(&self) -> Option<(&str, Option<&str>)> {","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/rust-lang/rust-analyzer/blob/e8f7e90aa3e7b26aa9a000200f606c1078da99ec/crates/paths/src/lib.rs#L233-L269","documentation":"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).","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nlet canon = abs_path.canonicalize();\n// after\nlet canon: std::io::Result<AbsPathBuf> =\n    std::fs::canonicalize(abs_path.as_ref()).and_then(|p| Ok(AbsPathBuf::try_from(p)?));","handlingStrategy":"validation","validationCode":"fn safe_canonicalize(p: &AbsPath) -> std::io::Result<AbsPathBuf> {\n    std::fs::canonicalize(p.as_ref()).map(|q| AbsPathBuf::try_from(q).unwrap())\n}","typeGuard":"// AbsPath exposes no canonicalize; guard by feature-checking in your own code\nfn supports_canonicalize() -> bool { false }","tryCatchPattern":null,"preventionTips":["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"],"tags":["rust","paths","panic","api-removed"],"backgroundTag":"intentional-panic-api","analyzedSha":"e8f7e90aa3e7b26aa9a000200f606c1078da99ec","analyzedAt":"2026-09-03T21:08:06.959Z","contentChangedAt":"2026-09-03T21:08:06.959Z","schemaVersion":2},"datasetVersion":"2026-09-11T07:07:21.782Z"}