gleam-lang/gleam · error

Source path should be under base

Error message

Source path should be under base

What it means

hardlink_dir computes each entry's path relative to the walk base with strip_prefix(base).expect("Source path should be under base") and panics if the entry is not under the base directory. With symlink following enabled (or a symlink escaping the tree), ignore::Walk can yield entries whose canonical paths are outside base, breaking this invariant and aborting the process.

Solutions

  1. Remove or fix symlinks in the source directory that point outside the base tree (`find <source> -type l -ls` to list them), then retry.
  2. Ensure symlinks are relative and stay within the base directory before running the hardlink operation.
  3. In the crate, avoid following symlinks (do not enable follow_links in the WalkBuilder) or replace the expect with a map_err that returns Error::FileIo for out-of-base entries.

Example fix

// before
let relative = source_path
    .strip_prefix(base)
    .expect("Source path should be under base");

// after
let relative = source_path.strip_prefix(base).map_err(|_| Error::FileIo {
    action: FileIoAction::Read,
    kind: FileKind::File,
    path: source_path.to_string(),
    err: Some("entry is not under the hardlink base directory".into()),
})?;
Defensive patterns

Strategy: validation

Validate before calling

// Rust: ensure no symlink in the source tree escapes the base directory
fn symlinks_stay_within(base: &std::path::Path) -> bool {
    walkdir::WalkDir::new(base).follow_links(false).into_iter()
        .filter_map(Result::ok)
        .filter(|e| e.file_type().is_symlink())
        .all(|e| {
            std::fs::read_link(e.path())
                .ok()
                .and_then(|l| base.join(l).canonicalize().ok())
                .map(|c| c.starts_with(base))
                .unwrap_or(false)
        })
}

Type guard

fn is_within_base(base: &std::path::Path, p: &std::path::Path) -> bool {
    p.starts_with(base)
}

Prevention

When it happens

Trigger: Calling compiler_cli::fs::hardlink_dir(base, dest) when the source tree contains a symlink pointing outside the base directory (e.g. a symlink to an absolute path or ../somewhere), so the walked entry path does not start with base.

Common situations: Source trees with symlinks into shared dependency folders; node_modules-style links; symlinked build-output directories; copying a project that was assembled with cross-directory links.

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/fd7dcbe6c11f4166. Report an issue: GitHub.

Appendix: source

Thrown at compiler-cli/src/fs.rs:772

        kind: FileKind::Directory,
        path: current.to_path_buf(),
        err: Some(err.to_string()),
    })?;

    for entry in entries {
        let entry = entry.map_err(|err| Error::FileIo {
            action: FileIoAction::Read,
            kind: FileKind::Directory,
            path: current.to_path_buf(),
            err: Some(err.to_string()),
        })?;

        let source_path =
            Utf8PathBuf::from_path_buf(entry.path()).expect("Non-UTF8 path in hardlink_dir");

        let relative = source_path
            .strip_prefix(base)
            .expect("Source path should be under base");
        let dest_path = dest_base.join(relative);

        let file_type = entry.file_type().map_err(|err| Error::FileIo {
            action: FileIoAction::Read,
            kind: FileKind::File,
            path: source_path.clone(),
            err: Some(err.to_string()),
        })?;

        // Skip symlinks to prevent path traversal outside the source tree
        if file_type.is_symlink() {
            tracing::trace!(path=?source_path, "skipping_symlink_in_hardlink_dir");
            continue;
        }

        if file_type.is_dir() {
            mkdir(&dest_path)?;
            hardlink_dir_recursive(base, &source_path, dest_base)?;

View on GitHub (pinned to 15b07c7830)