gleam-lang/gleam · error

is_gleam_path(): strip_prefix

Error message

is_gleam_path(): strip_prefix

What it means

A panic from `path.strip_prefix(dir)` inside `is_gleam_path`: a directory entry produced by the walker does not start with the root `dir` being scanned, so the library cannot compute the module-relative path to match against the Gleam path regex. This indicates the walked paths and the configured root disagree.

Solutions

  1. Canonicalise the directory before scanning: `let dir = Utf8PathBuf::from_path_buf(dir.canonicalize().expect("dir"))?;` so walker entries and the root share one form.
  2. Use the same absolute, resolved path form consistently when constructing the project's src/test directory handles.
  3. Avoid symlinked source directories, or point `dir` at the symlink target instead.
  4. If it reproduces with plain absolute paths, file a bug upstream with the OS and exact `dir` value.

Example fix

// before
let files: Vec<_> = gleam_files(&Utf8Path::new("src")).collect();
// after
let dir = Utf8PathBuf::from_path_buf(
    std::fs::canonicalize("src").expect("canonicalise src"),
)
.expect("utf-8");
let files: Vec<_> = gleam_files(&dir).collect();
Defensive patterns

Strategy: validation

Validate before calling

// canonicalise and verify containment before scanning
let dir = Utf8PathBuf::from_path_buf(dir.canonicalize()?).map_err(|_| anyhow!("non-utf8 dir"))?;
assert!(Path::new("src/lib.gleam").starts_with(&dir), "source dirs must live under dir");

Type guard

fn is_under(dir: &Utf8Path, p: &Path) -> bool { p.strip_prefix(dir).is_ok() }

Try / catch

std::panic::catch_unwind(|| gleam_files(&dir).collect::<Vec<_>>())
    .map_err(|_| anyhow!("path root mismatch while scanning gleam files"))?

Prevention

When it happens

Trigger: Calling `gleam_files(dir)` where entries yielded by the `ignore::Walk` are not under `dir` — e.g. `dir` was passed with a different form (uncanonicalised, symlinked, or with different case/separator handling) than the paths the walker returns.

Common situations: Passing a path through a symlink so the walker resolves entries to the real path while `dir` remains the symlink path (or vice versa); passing a relative `dir` while entries come back absolute; Windows drive-letter casing mismatches (C:\ vs c:\).

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

Appendix: source

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

            err: Some(error.to_string()),
        })
}

static IS_GLEAM_PATH_PATTERN: OnceLock<Regex> = OnceLock::new();

fn is_gleam_path(path: &Utf8Path, dir: impl AsRef<Utf8Path>) -> bool {
    IS_GLEAM_PATH_PATTERN
        .get_or_init(|| {
            Regex::new(&format!(
                "^({module}{slash})*{module}\\.gleam$",
                module = "[a-z][_a-z0-9]*",
                slash = "(/|\\\\)",
            ))
            .expect("is_gleam_path() RE regex")
        })
        .is_match(
            path.strip_prefix(dir.as_ref())
                .expect("is_gleam_path(): strip_prefix")
                .as_str(),
        )
}

fn is_gleam_build_dir(e: &ignore::DirEntry) -> bool {
    if !e.path().is_dir() || !e.path().ends_with("build") {
        return false;
    }

    let Some(parent_path) = e.path().parent() else {
        return false;
    };

    parent_path.join("gleam.toml").exists()
}

/// Walks through all Gleam module files in the directory, even if ignored,
/// except for those in the `build/` directory. Excludes any Gleam files within

View on GitHub (pinned to 15b07c7830)