{"record":{"id":"e99029746c6abed5","repo":"rust-lang/mdBook","slug":"one-of-the-paths-should-be-an-absolute-e99029","errorCode":null,"errorMessage":"One of the paths should be an absolute","messagePattern":"One of the paths should be an absolute","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/cmd/watch/poller.rs","lineNumber":171,"sourceCode":"    fn scan(&mut self) -> Vec<PathBuf> {\n        let ignore = &self.ignore;\n        let new_path_data: HashMap<_, _> = self\n            .root_paths\n            .iter()\n            .filter(|root| root.exists())\n            .flat_map(|root| {\n                WalkDir::new(root)\n                    .follow_links(true)\n                    .into_iter()\n                    .filter_entry(|entry| {\n                        if let Some((ignore_path, ignore)) = ignore {\n                            let path = entry.path();\n                            // Canonicalization helps with removing `..` and\n                            // `.` entries, which can cause issues with\n                            // diff_paths.\n                            let path = path.canonicalize().unwrap_or_else(|_| path.to_path_buf());\n                            let relative_path = diff_paths(&path, &ignore_path)\n                                .expect(\"One of the paths should be an absolute\");\n                            if ignore\n                                .matched_path_or_any_parents(&relative_path, relative_path.is_dir())\n                                .is_ignore()\n                            {\n                                trace!(\"ignoring {path:?}\");\n                                return false;\n                            }\n                        }\n                        true\n                    })\n                    .filter_map(move |entry| {\n                        let entry = match entry {\n                            Ok(e) => e,\n                            Err(e) => {\n                                debug!(\"failed to scan {root:?}: {e}\");\n                                return None;\n                            }\n                        };","sourceCodeStart":153,"sourceCodeEnd":189,"githubUrl":"https://github.com/rust-lang/mdBook/blob/dc21064fc21d955a0e1f67e65e336883c3e5260b/src/cmd/watch/poller.rs#L153-L189","documentation":"During `scan`, poller.rs canonicalizes each directory-entry path (falling back to the raw path on failure) and then calls `diff_paths(&path, &ignore_path).expect(\"One of the paths should be an absolute\")`. If the entry path cannot be made relative to the canonicalized ignore root — different drive/prefix, differing canonical forms — diff_paths yields None and the expect panics the watcher.","triggerScenarios":"A scanned file path resolves to a different drive/UNC prefix than the canonicalized ignore root on Windows; canonicalize fails on an entry (broken symlink) leaving a path form incompatible with the ignore root; ignore root changed identity after being cached in the poller.","commonSituations":"Windows cross-drive setups; symlinked book subdirectories; files whose canonicalization fails (deleted mid-scan) while the root is canonical, producing None from diff_paths.","solutions":["Keep the entire book tree on the same drive/prefix as its .gitignore.","Handle diff_paths None gracefully: `match diff_paths(...) { Some(r) => ..., None => return true }` instead of expect.","Ensure the ignore_path cached in `new` is still valid/canonical relative to scanned entries.","Remove broken symlinks from the watched tree or exclude them from scanning."],"exampleFix":"// before\nlet relative_path = diff_paths(&path, &ignore_path)\n    .expect(\"One of the paths should be an absolute\");\n// after\nlet Some(relative_path) = diff_paths(&path, &ignore_path) else {\n    trace!(\"could not relativize {path:?} against {ignore_path:?}\");\n    return true;\n};","handlingStrategy":"fallback","validationCode":"// before scanning, ensure entry relativizes against the cached root\nif diff_paths(&entry.path().canonicalize().unwrap_or_else(|_| entry.path().to_path_buf()), &ignore_path).is_none() {\n    trace!(\"skipping path outside ignore root prefix\");\n}","typeGuard":null,"tryCatchPattern":"let Some(relative_path) = diff_paths(&path, &ignore_path) else {\n    trace!(\"diff_paths returned None for {path:?}\");\n    return true; // treat as not-ignored rather than panic\n};","preventionTips":["Canonicalize each scanned entry (as poller.rs already does) before diffing.","Keep the whole watched tree on one drive/prefix on Windows.","Exclude or clean up broken symlinks in the watched tree.","Handle diff_paths None explicitly instead of expect."],"tags":["filesystem","panic","pathdiff","windows","poller"],"backgroundTag":"relative-path-conversion-failed","analyzedSha":"dc21064fc21d955a0e1f67e65e336883c3e5260b","analyzedAt":"2026-09-01T10:15:12.134Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T15:18:49.778Z"}