{"record":{"id":"fd2eec3276a14302","repo":"GitoxideLabs/gitoxide","slug":"prefix-stripping-cannot-fail-as-base-is-within-our","errorCode":null,"errorMessage":"prefix-stripping cannot fail as base is within our root","messagePattern":"prefix-stripping cannot fail as base is within our root","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"gix-ref/src/store/file/loose/iter.rs","lineNumber":59,"sourceCode":"            }),\n        }\n    }\n}\n\nimpl Iterator for SortedLoosePaths {\n    type Item = std::io::Result<(PathBuf, FullName)>;\n\n    fn next(&mut self) -> Option<Self::Item> {\n        for entry in self.file_walk.as_mut()?.by_ref() {\n            match entry {\n                Ok(entry) => {\n                    if !entry.file_type().is_ok_and(|ft| ft.is_file()) {\n                        continue;\n                    }\n                    let full_path = entry.path().into_owned();\n                    let full_name = full_path\n                        .strip_prefix(&self.base)\n                        .expect(\"prefix-stripping cannot fail as base is within our root\");\n                    let Ok(full_name) = gix_path::try_into_bstr(full_name)\n                        .map(|name| gix_path::to_unix_separators_on_windows(name).into_owned())\n                    else {\n                        continue;\n                    };\n                    if let Some(prefix) = &self.prefix\n                        && !full_name.starts_with(prefix)\n                    {\n                        continue;\n                    }\n                    if let Some(suffix) = &self.suffix\n                        && !full_name.ends_with(suffix)\n                    {\n                        continue;\n                    }\n                    if gix_validate::reference::name_partial(full_name.as_bstr()).is_ok() {\n                        let name = FullName(full_name);\n                        return Some(Ok((full_path, name)));","sourceCodeStart":41,"sourceCodeEnd":77,"githubUrl":"https://github.com/GitoxideLabs/gitoxide/blob/e73179060badf27222d790981fac3f84c1830a7e/gix-ref/src/store/file/loose/iter.rs#L41-L77","documentation":"A Rust `expect()` panic in the loose-refs directory iterator's `next()` (gix-ref/store/file/loose/iter.rs). For each file entry it strips the store's `base` directory prefix from the entry path, asserting the entry is always inside the base since both come from walking the same root. It panics if `self.base` and the walked root diverge — e.g. the base path differs from the directory handed to `std::fs::read_dir` (symlink resolution differences, non-canonicalized paths like `./refs` vs `refs`, or path casing/format mismatches on Windows).","triggerScenarios":"Creating a `loose::Iter` with a `base` that is not the canonicalized same path as the directory being traversed (e.g. base contains `..`, a symlink, or a trailing separator while read_dir resolves differently); platform-specific path normalization (`\\\\?\\` prefixes, case differences) breaking `strip_prefix`.","commonSituations":"Passing relative or non-canonical repository paths (`./.git/refs`, symlinked `.git` dirs) into low-level loose-ref iteration; using a different path form for base vs the traversal root; Windows path quirks.","solutions":["Canonicalize both the base and the directory before constructing the iterator (`std::fs::canonicalize`) so `strip_prefix` matches.","Ensure the exact same `PathBuf` value is used for the base and the traversal root — avoid rebuilding the path separately.","Resolve symlinks (especially symlinked `.git` or `refs` directories) before iteration.","If it occurs on canonicalized paths, report upstream with the OS and path strings — internal invariant violation."],"exampleFix":"// before\nlet base = PathBuf::from(\"./.git/refs\");\nlet iter = loose::Iter::at(dir_read_from_symlinked_path, base, ...); // panic\n// after\nlet base = std::fs::canonicalize(\"./.git/refs\")?;\nlet iter = loose::Iter::at(base.clone(), base, ...); // identical canonical paths","handlingStrategy":"validation","validationCode":"let base = std::fs::canonicalize(\".git/refs\")?;\nassert_eq!(base, dir_being_walked_canonicalized); // base must equal traversal root","typeGuard":"fn same_root(base: &Path, root: &Path) -> bool {\n    std::fs::canonicalize(base).ok().as_deref() == std::fs::canonicalize(root).ok().as_deref()\n}","tryCatchPattern":null,"preventionTips":["Canonicalize paths before constructing loose iterators","Use the identical PathBuf for base and traversal root","Resolve symlinked .git directories up front"],"tags":["rust","panic","path-handling","loose-refs"],"backgroundTag":"internal-invariant-violation","analyzedSha":"e73179060badf27222d790981fac3f84c1830a7e","analyzedAt":"2026-09-08T11:26:50.865Z","contentChangedAt":"2026-09-08T11:26:50.865Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}