{"record":{"id":"c3dcfa19232a1d7d","repo":"gleam-lang/gleam","slug":"should-not-fail-on-two-absolute-paths","errorCode":null,"errorMessage":"Should not fail on two absolute paths","messagePattern":"Should not fail on two absolute paths","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler-core/src/io.rs","lineNumber":58,"sourceCode":"/// Takes in a source path and a target path and determines a relative path\n/// from source -> target.\n/// If given a relative target path, no calculation occurs.\n/// # Panics\n/// The provided source path should be absolute, otherwise will panic.\npub fn make_relative(source_path: &Utf8Path, target_path: &Utf8Path) -> Utf8PathBuf {\n    assert!(source_path.is_absolute());\n    // Input target will always be canonicalised whereas source will not\n    // This causes problems with diffing on windows since canonicalised paths have a special root\n    // As such we are attempting to strip the target path\n    // Based on https://github.com/rust-lang/rust/issues/42869#issuecomment-1712317081\n    #[cfg(target_family = \"windows\")]\n    let binding = target_path.to_string();\n    #[cfg(target_family = \"windows\")]\n    let target_path = Utf8Path::new(binding.trim_start_matches(r\"\\\\?\\\"));\n\n    match target_path.is_absolute() {\n        true => pathdiff::diff_utf8_paths(target_path, source_path)\n            .expect(\"Should not fail on two absolute paths\"),\n\n        false => target_path.into(),\n    }\n}\n\npub trait Reader: io::Read {\n    /// A wrapper around `std::io::Read` that has Gleam's error handling.\n    fn read_bytes(&mut self, buffer: &mut [u8]) -> Result<usize> {\n        self.read(buffer).map_err(|error| self.convert_err(error))\n    }\n\n    fn convert_err<E: std::error::Error>(&self, error: E) -> Error;\n}\n\npub trait Utf8Writer: std::fmt::Write {\n    /// A wrapper around `fmt::Write` that has Gleam's error handling.\n    fn str_write(&mut self, str: &str) -> Result<()> {\n        self.write_str(str).map_err(|error| self.convert_err(error))","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/gleam-lang/gleam/blob/15b07c783065c92bb016b1b74ed0995a5259850f/compiler-core/src/io.rs#L40-L76","documentation":"`make_relative` panics when `pathdiff::diff_utf8_paths` returns None despite both paths being asserted absolute. pathdiff returns None when the two paths have different prefixes (notably on Windows: different drives like C:\\ vs D:\\), so the 'two absolute paths always relativizable' assumption is false.","triggerScenarios":"Calling `make_relative` (via `to_toml`) where source_path and target_path are absolute but on different Windows drives, or where one path's prefix differs (UNC vs drive letter), making diff_utf8_paths return None.","commonSituations":"Gleam projects on Windows with output/target on a different drive than the package source; publishing paths config (`gleam.toml` doc/output paths) spanning drives.","solutions":["Ensure source_path and target_path live on the same drive/volume (Windows).","Handle the None case: fall back to the absolute target path instead of expecting.","Check target_path.is_absolute() after diff and use the original absolute path when diffing fails."],"exampleFix":"// before\npathdiff::diff_utf8_paths(target_path, source_path)\n    .expect(\"Should not fail on two absolute paths\")\n// after\npathdiff::diff_utf8_paths(target_path, source_path)\n    .unwrap_or_else(|| target_path.to_owned())","handlingStrategy":"try-catch","validationCode":"let same_prefix = source_path.components().next() == target_path.components().next(); if target_path.is_absolute() && !same_prefix { /* expect failure on Windows */ }","typeGuard":null,"tryCatchPattern":"// Rust panics cannot be caught except via catch_unwind\nlet rel = pathdiff::diff_utf8_paths(target, source).unwrap_or_else(|| target.to_owned());","preventionTips":["Keep source and target paths on the same Windows drive.","Handle pathdiff's None case explicitly instead of expecting.","Trim Windows \\\\?\\ prefixes before diffing (as the function already does)."],"tags":["rust","paths","windows","panic"],"backgroundTag":"internal-invariant-violation","analyzedSha":"15b07c783065c92bb016b1b74ed0995a5259850f","analyzedAt":"2026-09-14T11:14:59.388Z","contentChangedAt":"2026-09-14T11:14:59.388Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}