gleam-lang/gleam · error
Non-UTF8 path in hardlink_dir
Error message
Non-UTF8 path in hardlink_dir
What it means
hardlink_dir recursively hard-links a directory tree; for every walked entry it converts entry.path() to Utf8PathBuf with .expect("Non-UTF8 path in hardlink_dir"). Since the crate only models UTF-8 paths, a directory entry whose name contains invalid UTF-8 bytes panics with 'Non-UTF8 path in hardlink_dir'. This is an internal invariant assertion, not a recoverable error.
Solutions
- Scan the source directory for non-UTF-8 names (`find <source> -print0 | LC_ALL=C grep -zP '[\x80-\xFF]'`) and rename or delete them, then retry.
- Regenerate the source directory contents from a trusted source so all names are UTF-8.
- In the crate, replace the expect with a propagated Error::FileIo (or skip the entry) so a stray file yields a diagnostic rather than a panic mid-build.
Example fix
// before
let source_path =
Utf8PathBuf::from_path_buf(entry.path()).expect("Non-UTF8 path in hardlink_dir");
// after
let source_path = Utf8PathBuf::from_path_buf(entry.path()).map_err(|p| Error::FileIo {
action: FileIoAction::Read,
kind: FileKind::File,
path: p.display().to_string(),
err: Some("non-UTF8 path in hardlink_dir".into()),
})?; Defensive patterns
Strategy: validation
Validate before calling
// Rust: verify the hardlink source tree is UTF-8-clean before calling hardlink_dir
fn source_paths_utf8(source: &std::path::Path) -> bool {
walkdir::WalkDir::new(source)
.into_iter()
.filter_map(Result::ok)
.all(|e| e.path().to_str().is_some())
} Type guard
fn is_utf8_path(p: &std::path::Path) -> bool {
p.to_str().is_some()
} Prevention
- Only hardlink directory trees produced by trusted UTF-8-safe tooling.
- Scan the source directory for non-UTF-8 names before caching/linking operations.
- Regenerate build-cache directories rather than reusing ones from other machines/locales.
- Patch the crate to propagate a FileIo error instead of panicking on non-UTF-8 entries.
When it happens
Trigger: Calling compiler_cli::fs::hardlink_dir(source, dest) where the source tree contains any file or subdirectory with a non-UTF-8 name.
Common situations: Build cache directories or dependency checkouts containing files with byte-mangled names; artifacts unpacked from archives with non-UTF-8 entry names; files created under a non-UTF-8 locale then used in a UTF-8 build environment.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Non Utf8 Path
- Source path should be under base
- is_gleam_path(): strip_prefix
- Non Utf-8 Path
- Non Utf-8 Path
AI-assisted analysis of gleam-lang/gleam@15b07c7830 (2026-09-14).
Data as JSON: /api/errors/e94246bad09676f9.
Report an issue: GitHub.
Appendix: source
Thrown at compiler-cli/src/fs.rs:768
dest_base: &Utf8Path,
) -> Result<(), Error> {
let entries = std::fs::read_dir(current).map_err(|err| Error::FileIo {
action: FileIoAction::Read,
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;
}View on GitHub (pinned to 15b07c7830)