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 (compiler-core/src/io.rs:45) computes a path from target back to source using pathdiff::diff_utf8_paths and expects Some whenever the target is absolute (the source is asserted absolute on the line above). pathdiff returns None when the two absolute paths have incompatible prefixes — on Windows that means different drive letters or a UNC vs local-drive mismatch (the `\\?\` strip only removes the verbatim prefix, not drive differences). So this panic is a Windows-specific path-prefix mismatch, not general corruption.
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(|e| self.convert_err(e))
}
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(|e| self.convert_err(e))View on GitHub (pinned to 7e623aa83d)
Solutions
- Keep every component of the project (sources, build dir, caches, git dependencies) on the same Windows drive — check where your HOME/HOMEDRIVE points if caches live there.
- Replace UNC/mapped-drive paths with a local drive path (copy the project off the network share) before building.
- If you call make_relative as a library, pre-check `pathdiff::diff_utf8_paths(target, source).is_none()` and fall back to using the absolute target path.
- Report upstream: make_relative could gracefully fall back to the absolute target when prefixes differ instead of expect().
Example fix
// before: panics when prefixes differ (C: vs D:, UNC vs drive)
let rel = gleam_core::io::make_relative(&source, &target);
// after: guard the incompatible-prefix case
let rel = match pathdiff::diff_utf8_paths(&target, &source) {
Some(diff) => diff,
None => target.to_path_buf(), // cross-drive: keep absolute
}; Defensive patterns
Strategy: validation
Validate before calling
// On Windows, verify the two paths share a prefix before diffing
use camino::Utf8Path;
fn same_prefix(a: &Utf8Path, b: &Utf8Path) -> bool {
match (a.components().next(), b.components().next()) {
(Some(x), Some(y)) => x == y, // Prefix (drive/UNC) equality
_ => false,
}
}
// only call make_relative when compatible; otherwise use the absolute path
let rel = if same_prefix(source, target) {
make_relative(source, target)
} else {
target.to_path_buf()
}; Prevention
- Keep project, build directory, and caches on one drive letter on Windows.
- Avoid building from UNC network paths (\\server\share) or subst-mapped drives.
- Library callers: pre-check `pathdiff::diff_utf8_paths(target, source).is_some()` and fall back to the absolute target.
When it happens
Trigger: Windows builds where the canonicalised target path and the absolute source path live on different drives — e.g. project on C: but a package/build path resolved to D:, or a source path expressed as a UNC share (\\server\share) while the target canonicalised to a mapped drive. `pathdiff::diff_utf8_paths(d:\x, c:\y)` → None → panic.
Common situations: Windows developers with GLEAM caches/build dirs redirected to another drive; projects on network shares or subst-mapped drives; CI on windows-lu runners where workspace and toolchain/virtual-store paths straddle drives.
Related errors
- `panic` expression evaluated.
- Writing warning to stderr
- Final result error writing
- joining_lsp_threads
- invalid folder
AI-assisted analysis of gleam-lang/gleam@7e623aa83d (2026-08-17).
Data as JSON: /api/errors/c3dcfa19232a1d7d.
Report an issue: GitHub.