rust-lang/rust · error

Failed to read contents of {path}: {err}

Error message

Failed to read contents of {path}: {err}

What it means

This `panic!` fires inside `ensure_empty_dir` (utils.rs:180) when `fs::read_dir(path)` returns an error other than `NotFound`. `NotFound` is tolerated (nothing to clear), but failures such as `PermissionDenied`, a broken symlink, or an unreadable directory abort the cranelift build-system immediately. The path (already `create_dir_all`'d on the line above) and the OS error are formatted into the message.

Source

Thrown at compiler/rustc_codegen_cranelift/build_system/utils.rs:188

#[track_caller]
pub(crate) fn spawn_and_wait(mut cmd: Command) {
    let status = cmd.spawn().unwrap().wait().unwrap();
    if !status.success() {
        eprintln!("{cmd:?} exited with status {:?}", status);
        process::exit(1);
    }
}

/// Create the specified directory if it doesn't exist yet and delete all contents.
pub(crate) fn ensure_empty_dir(path: &Path) {
    fs::create_dir_all(path).unwrap();
    let read_dir = match fs::read_dir(path) {
        Ok(read_dir) => read_dir,
        Err(err) if err.kind() == io::ErrorKind::NotFound => {
            return;
        }
        Err(err) => {
            panic!("Failed to read contents of {path}: {err}", path = path.display())
        }
    };
    for entry in read_dir {
        let entry = entry.unwrap();
        if entry.file_type().unwrap().is_dir() {
            match fs::remove_dir_all(entry.path()) {
                Ok(()) => {}
                Err(err) if err.kind() == io::ErrorKind::NotFound => {}
                Err(err) => panic!("Failed to remove {path}: {err}", path = entry.path().display()),
            }
        } else {
            match fs::remove_file(entry.path()) {
                Ok(()) => {}
                Err(err) if err.kind() == io::ErrorKind::NotFound => {}
                Err(err) => panic!("Failed to remove {path}: {err}", path = entry.path().display()),
            }
        }
    }

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Read the `err` field: `PermissionDenied` ⇒ `sudo chown -R $USER:$USER <path>` or `chmod -R u+rX <path>`.
  2. Manually wipe and recreate the path printed in the panic: `rm -rf <path> && mkdir -p <path>`, then re-run the build.
  3. Check for SELinux/AppArmor denials (`ausearch -m avc` / `dmesg`) and label the build tree accordingly.
  4. Move the build dir off network/FUSE filesystems onto a local ext4/xfs volume.
  5. Re-run from a clean slate: `./y.sh clean && ./y.sh prepare`.

Example fix

# before — ensure_empty_dir panics with PermissionDenied
./y.sh prepare
# panics: Failed to read contents of /path/dir: Permission denied

# after — fix perms then re-run
sudo chown -R $USER:$USER /path/dir
chmod -R u+rX /path/dir
./y.sh prepare
Defensive patterns

Strategy: validation

Validate before calling

// utils.rs read failure — the build tried to read a path that is missing,
// unreadable, or wrong. Validate existence + readability BEFORE invoking:
use std::path::Path;
fn readable(p: &Path) -> std::io::Result<()> {
    let md = std::fs::metadata(p)?;
    if md.is_dir() { return Err(std::io::Error::new(std::io::ErrorKind::IsADirectory, "is dir")); }
    if md.permissions().readonly() { /* still readable, ok */ }
    std::fs::read(p).map(|_| ()) // prove we can actually read the bytes
}
// Call readable(&path)? before the build step that consumes it.

Try / catch

// Read defensively in your own driver, surfacing the exact cause:
fn read_or_diag(p: &std::path::Path) -> Vec<u8> {
    match std::fs::read(p) {
        Ok(b) => b,
        Err(e) => {
            eprintln!("read failed: {:?} kind={:?} exists={}",
                p, e.kind(), p.exists());
            std::process::exit(1);
        }
    }
}

Prevention

When it happens

Trigger: Triggered when the cranelift build calls `ensure_empty_dir(target_dir)` (or any other path managed by `utils.rs`) and `read_dir` at line 182 returns an I/O error other than `NotFound`. Because `create_dir_all` succeeded one line earlier, this usually means the dir was created but is unreadable (mode bits, ACL, SELinux label, or a dangling symlink somewhere under it).

Common situations: Surfaces in CI or local cranelift builds when the target/download dir was created by a different user (e.g. an earlier `sudo ./y.sh`), when SELinux/AppArmor deny directory reads, or when the dir lives on a filesystem (FUSE, network) that fails `read_dir` transiently. Also seen after a crashed build leaves the tree in a half-state.

Related errors


AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03). Data as JSON: /data/errors/88c27891036948b9.json. Report an issue: GitHub.