{"record":{"id":"eeec336d6ec93788","repo":"vercel/turborepo","slug":"collapsed-path-should-be-absolute-err","errorCode":null,"errorMessage":"collapsed path should be absolute: {err:?}","messagePattern":"collapsed path should be absolute: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/turborepo-paths/src/absolute_system_path.rs","lineNumber":404,"sourceCode":"                }\n                Utf8Component::ParentDir => {\n                    // should error if there's nothing popped\n                    stack.pop();\n                }\n                c => stack.push(c),\n            }\n        }\n        debug_assert!(\n            matches!(\n                stack.first(),\n                Some(Utf8Component::RootDir) | Some(Utf8Component::Prefix(_))\n            ),\n            \"expected absolute path to start with root/prefix\"\n        );\n\n        match AbsoluteSystemPathBuf::new(stack.into_iter().collect::<Utf8PathBuf>()) {\n            Ok(path) => path,\n            Err(err) => panic!(\"collapsed path should be absolute: {err:?}\"),\n        }\n    }\n\n    // TODO: consider consolidating with `relation_to_path` below\n    pub fn contains(&self, other: &Self) -> bool {\n        // On windows, trying to get a relative path between files on different volumes\n        // is an error. We don't care about the error, it's good enough for us to say\n        // that one path doesn't contain the other if they're on different volumes.\n        #[cfg(windows)]\n        if self.components().next() != other.components().next() {\n            return false;\n        }\n        let this = self.collapse();\n        let other = other.collapse();\n        let rel = AnchoredSystemPathBuf::relative_path_between(&this, &other);\n        rel.components().next() != Some(Utf8Component::ParentDir)\n    }\n","sourceCodeStart":386,"sourceCodeEnd":422,"githubUrl":"https://github.com/vercel/turborepo/blob/f9245100cf0d31d96628804ead485f6bf226e55a/crates/turborepo-paths/src/absolute_system_path.rs#L386-L422","documentation":"collapse() resolves `.`/`..` components by walking a component stack and rebuilding a Utf8PathBuf; the first component was just debug_asserted to be a root/prefix component, so the following AbsoluteSystemPathBuf::new can only fail if that invariant is already broken. Pure internal invariant panic in turborepo-paths.","triggerScenarios":"Internal misuse or regression in the component-collapsing algorithm only; there is no user input that legitimately reaches it.","commonSituations":"Would manifest as a turbo crash during path normalization after an internal bug; not config-triggerable.","solutions":["Upgrade turborepo","Report a minimal reproduction (the exact path string) if it recurs"],"exampleFix":null,"handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"let cleaned = std::panic::catch_unwind(|| collapse(&path));\nif let Ok(p) = cleaned { use(p) } else { use(path.clone()) /* skip collapsing */ }","preventionTips":["Treat any reproduction as a bug: capture the input path string and report it upstream","Pin turborepo versions and test path-heavy workloads (large monorepos) after upgrades"],"tags":["rust","panic","path","invariant","normalization"],"backgroundTag":"path-invariant-panic","analyzedSha":"f9245100cf0d31d96628804ead485f6bf226e55a","analyzedAt":"2026-08-17T10:46:15.696Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}