{"record":{"id":"eec963370dc0a8dc","repo":"vercel/turborepo","slug":"joined-path-is-absolute-and-valid-utf8-err","errorCode":null,"errorMessage":"joined path is absolute and valid utf8: {err:?}","messagePattern":"joined path is absolute and valid utf8: (.+?)","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"crates/turborepo-paths/src/absolute_system_path.rs","lineNumber":270,"sourceCode":"        debug_assert!(\n            !segments\n                .iter()\n                .any(|segment| segment.contains(std::path::MAIN_SEPARATOR))\n        );\n        AbsoluteSystemPathBuf(clean_utf8_path(\n            self.0.join(segments.join(std::path::MAIN_SEPARATOR_STR)),\n        ))\n    }\n\n    pub fn as_str(&self) -> &str {\n        self.0.as_str()\n    }\n\n    pub fn join_unix_path(&self, unix_path: impl AsRef<RelativeUnixPath>) -> AbsoluteSystemPathBuf {\n        let tail = unix_path.as_ref().to_system_path_buf();\n        AbsoluteSystemPathBuf(match self.0.join(tail).as_std_path().clean().try_into() {\n            Ok(path) => path,\n            Err(err) => panic!(\"joined path is absolute and valid utf8: {err:?}\"),\n        })\n    }\n\n    /// Joins a normalized relative Unix path without resolving `.` or `..`.\n    /// Use `join_unix_path` unless the caller knows the path is normalized.\n    pub fn join_unix_path_unchecked(\n        &self,\n        unix_path: impl AsRef<RelativeUnixPath>,\n    ) -> AbsoluteSystemPathBuf {\n        #[cfg(unix)]\n        {\n            AbsoluteSystemPathBuf(self.0.join(unix_path.as_ref().as_str()))\n        }\n\n        #[cfg(windows)]\n        {\n            let tail = unix_path.as_ref().to_system_path_buf();\n            AbsoluteSystemPathBuf(self.0.join(tail))","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/vercel/turborepo/blob/f9245100cf0d31d96628804ead485f6bf226e55a/crates/turborepo-paths/src/absolute_system_path.rs#L252-L288","documentation":"AbsoluteSystemPathBuf::join_unix_path joins a relative Unix path onto an absolute system path, cleans the result, and converts it back into an AbsoluteSystemPathBuf. The try_into can only fail if the joined path were not absolute or not valid UTF-8 — both impossible given the input types — so this panic is an invariant guard inside turborepo-paths.","triggerScenarios":"Only via a bug or by bypassing the type's checked constructors (e.g., fabricating an AbsoluteSystemPathBuf from a relative string elsewhere in code) and then calling join_unix_path on it.","commonSituations":"Not reachable through turbo's public CLI; would appear as a crash in turbo's path handling after an internal regression.","solutions":["Upgrade turborepo to pick up path-handling fixes","In downstream Rust code, construct these types only via try_from/new so invariants hold","If reproducible, file an issue with the exact paths involved"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Only join genuine relative Unix paths onto absolute bases\nlet tail = RelativeUnixPathBuf::new(\"pkg/lib\")\n    .map_err(|e| format!(\"tail must be relative: {e:?}\"))?;\n// base came from a checked constructor, so the join invariant holds\nlet joined = base.join_unix_path(tail);","typeGuard":null,"tryCatchPattern":"let joined = std::panic::catch_unwind(|| base.join_unix_path(tail))\n    .unwrap_or_else(|_| fallback_to_std_join(&base, &tail));","preventionTips":["Construct AbsoluteSystemPathBuf only via new/try_from so the absolute-UTF-8 invariant holds","Never assemble these path types by hand through From<String> on unvalidated input","Contain turborepo-paths calls behind a process boundary in host applications"],"tags":["rust","panic","path","invariant","utf8"],"backgroundTag":"path-invariant-panic","analyzedSha":"f9245100cf0d31d96628804ead485f6bf226e55a","analyzedAt":"2026-08-17T10:46:15.696Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}