gleam-lang/gleam · error
Should not fail on two absolute paths
Error message
Should not fail on two absolute paths
What it means
`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.
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.
Example fix
// before
pathdiff::diff_utf8_paths(target_path, source_path)
.expect("Should not fail on two absolute paths")
// after
pathdiff::diff_utf8_paths(target_path, source_path)
.unwrap_or_else(|| target_path.to_owned()) Defensive patterns
Strategy: try-catch
Validate before calling
let same_prefix = source_path.components().next() == target_path.components().next(); if target_path.is_absolute() && !same_prefix { /* expect failure on Windows */ } Try / catch
// Rust panics cannot be caught except via catch_unwind let rel = pathdiff::diff_utf8_paths(target, source).unwrap_or_else(|| target.to_owned());
Prevention
- 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).
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
AI-assisted analysis of gleam-lang/gleam@15b07c7830 (2026-09-14).
Data as JSON: /api/errors/c3dcfa19232a1d7d.
Report an issue: GitHub.
Appendix: source
Thrown at compiler-core/src/io.rs:58
/// Takes in a source path and a target path and determines a relative path
/// from source -> target.
/// If given a relative target path, no calculation occurs.
/// # Panics
/// The provided source path should be absolute, otherwise will panic.
pub fn make_relative(source_path: &Utf8Path, target_path: &Utf8Path) -> Utf8PathBuf {
assert!(source_path.is_absolute());
// Input target will always be canonicalised whereas source will not
// This causes problems with diffing on windows since canonicalised paths have a special root
// As such we are attempting to strip the target path
// Based on https://github.com/rust-lang/rust/issues/42869#issuecomment-1712317081
#[cfg(target_family = "windows")]
let binding = target_path.to_string();
#[cfg(target_family = "windows")]
let target_path = Utf8Path::new(binding.trim_start_matches(r"\\?\"));
match target_path.is_absolute() {
true => pathdiff::diff_utf8_paths(target_path, source_path)
.expect("Should not fail on two absolute paths"),
false => target_path.into(),
}
}
pub trait Reader: io::Read {
/// A wrapper around `std::io::Read` that has Gleam's error handling.
fn read_bytes(&mut self, buffer: &mut [u8]) -> Result<usize> {
self.read(buffer).map_err(|error| self.convert_err(error))
}
fn convert_err<E: std::error::Error>(&self, error: E) -> Error;
}
pub trait Utf8Writer: std::fmt::Write {
/// A wrapper around `fmt::Write` that has Gleam's error handling.
fn str_write(&mut self, str: &str) -> Result<()> {
self.write_str(str).map_err(|error| self.convert_err(error))View on GitHub (pinned to 15b07c7830)