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

  1. 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.
  2. Replace UNC/mapped-drive paths with a local drive path (copy the project off the network share) before building.
  3. 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.
  4. 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

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


AI-assisted analysis of gleam-lang/gleam@7e623aa83d (2026-08-17). Data as JSON: /api/errors/c3dcfa19232a1d7d. Report an issue: GitHub.