rust-lang/rust · error
failed to mmap LTO bitcode file `{}`: {}
Error message
failed to mmap LTO bitcode file `{}`: {} What it means
Raised by SerializedModule::from_file in the LTO pipeline after a bitcode file was successfully opened but could not be memory-mapped. The panic happens inside Mmap::map, meaning the open() succeeded but the OS refused to map the file's bytes into the address space. rustc uses mmap here to avoid copying potentially large bitcode blobs pulled out of rlibs during fat/thin LTO.
Source
Thrown at compiler/rustc_codegen_ssa/src/back/lto.rs:61
pub modules: Vec<SerializedModule<B::ModuleBuffer>>,
pub module_names: Vec<CString>,
}
pub enum SerializedModule<M: ModuleBufferMethods> {
Local(M),
FromRlib(Vec<u8>),
FromUncompressedFile(Mmap),
}
impl<M: ModuleBufferMethods> SerializedModule<M> {
pub fn from_file(bc_path: &Path) -> Self {
let file = fs::File::open(&bc_path).unwrap_or_else(|e| {
panic!("failed to open LTO bitcode file `{}`: {}", bc_path.display(), e)
});
let mmap = unsafe {
Mmap::map(file).unwrap_or_else(|e| {
panic!("failed to mmap LTO bitcode file `{}`: {}", bc_path.display(), e)
})
};
SerializedModule::FromUncompressedFile(mmap)
}
pub fn data(&self) -> &[u8] {
match *self {
SerializedModule::Local(ref m) => m.data(),
SerializedModule::FromRlib(ref m) => m,
SerializedModule::FromUncompressedFile(ref m) => m,
}
}
}
fn crate_type_allows_lto(crate_type: CrateType) -> bool {
match crate_type {
CrateType::Executable
| CrateType::DylibView on GitHub (pinned to 22057b88b0)
Solutions
- Check the underlying errno from the panic message (PermissionDenied, ENOMEM, ENODEV, etc.) and address that specifically
- Free address space / raise vm.overcommit or RLIMIT_AS, or move to a 64-bit toolchain
- Move the cargo target dir off network/odd filesystems onto a local disk that supports mmap
- Ensure no second build is mutating the target directory concurrently (use a unique target dir per job)
- Disable LTO for the failing crate (-C lto=off) if the environment cannot mmap
Example fix
# before RUSTFLAGS="-C lto=fat" cargo build --release # after (on a no-mmap FS / memory-tight runner) RUSTFLAGS="-C lto=thin -C codegen-units=16" cargo build --release
Defensive patterns
Strategy: validation
Validate before calling
use std::path::Path;
use std::fs;
fn ensure_lto_bitcode_readable(path: &Path) -> std::io::Result<()> {
if !path.exists() {
return Err(std::io::Error::new(
std::io::ErrorKind::NotFound,
format!("LTO bitcode file not found: {}", path.display()),
));
}
let meta = fs::metadata(path)?;
if meta.len() == 0 {
return Err(std::io::Error::new(
std::io::ErrorKind::InvalidData,
"LTO bitcode file is empty (possible truncated write)",
));
}
let file = fs::File::open(path)?;
if file.metadata()?.permissions().readonly() {
// mmap of read-only is fine for LTO read; only warn if write-backed mmap expected
}
Ok(())
}
// before invoking the LTO/back-end entry point:
// ensure_lto_bitcode_readable(&path)?; Type guard
// mmap failure surfaces as std::io::Error; narrow on the kind rather than text.
fn is_mmap_error(e: &std::io::Error) -> bool {
matches!(
e.kind(),
std::io::ErrorKind::UnexpectedEof
| std::io::ErrorKind::InvalidData
| std::io::ErrorKind::PermissionDenied
| std::io::ErrorKind::OutOfMemory
) || e.raw_os_error().map_or(false, |c| {
// ENOMEM, EACCES, ENOENT, EFBIG, ENODEV, EOVERFLOW
matches!(c, 12 | 13 | 2 | 27 | 19 | 75)
})
} Try / catch
match lto::run(&path) {
Ok(out) => out,
Err(ref e) if is_mmap_error(e) => {
// transient (NFS, tmpfs pressure) -> one bounded retry with a fresh fd
eprintln!("warning: mmap failed for {}: {}; remapping", path.display(), e);
lto::run(&path).expect("mmap retry failed")
}
Err(e) => return Err(e.into()),
} Prevention
- Verify the bitcode file is fully flushed and closed on the producing side before the consuming side mmaps it (partial writes mmap as garbage).
- Avoid placing LTO bitcode on filesystems that do not support mmap (some FUSE mounts, network FS with mandatory locking); prefer local tmpfs/disk.
- Free address-space pressure before large LTO runs on 32-bit targets; close other mmaps first.
- Run with the same UID/GID that owns the bitcode file to avoid EACCES on mmap.
- Check free RAM and swap before LTO; mmap-backed reads still fault pages in and can OOM.
When it happens
Trigger: Mmap::map(file) returns Err immediately after fs::File::open succeeded, while constructing a SerializedModule for an LTO bitcode file. Concrete causes: file truncated/removed between open and mmap, mmap resource limits (RLIMIT_AS / vm.overcommit), filesystem that does not support mmap (some FUSE/NFS configs, certain network FS), file size of zero, or permission/SELinux denial on the map syscall.
Common situations: Building large crates with -C lto=fat or thin on memory-constrained CI runners; cross-compiling with bitcode stored on a network mount; /tmp mounted tmpfs with restrictive overcommit; concurrent builds mutating the same target dir; running out of address space under 32-bit toolchains.
Related errors
- couldn't map rlib
- couldn't open rlib
- Error writing pre-lto-bitcode file `{}`: {}
- wanted an rlib
- corrupt rlib
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/9364e24e64cff0ba.json.
Report an issue: GitHub.