rust-lang/rust · critical
failed to open LTO bitcode file `{}`: {}
Error message
failed to open LTO bitcode file `{}`: {} What it means
Thrown by SerializedModule::from_file when fs::File::open succeeds-or-panics on the given bitcode (.bc) path during LTO. If the file cannot be opened, rustc panics with the path and the underlying OS error instead of recovering, because a missing LTO bitcode input means incremental/LTO state is inconsistent and linking cannot proceed. A companion panic a few lines later covers the mmap step.
Source
Thrown at compiler/rustc_codegen_ssa/src/back/lto.rs:56
}
}
pub struct ThinShared<B: WriteBackendMethods> {
pub data: B::ThinData,
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,
}
}
}View on GitHub (pinned to 22057b88b0)
Solutions
- Run cargo clean and rebuild so all LTO bitcode is regenerated consistently.
- Ensure the build is not interrupted mid-LTO and that target/ is not partially deleted between runs.
- Check available disk space and write permissions on the target directory; LTO bitcode files are large.
- Avoid pointing CARGO_INCREMENTAL / INCR_COMP_SHARED_DIR at storage shared by concurrent rustc invocations.
Defensive patterns
Strategy: validation
Validate before calling
use std::fs::File;
use std::io::Read;
fn lto_bitcode_file_readable(path: &std::path::Path) -> bool {
let Ok(mut f) = File::open(path) else { return false; };
let mut magic = [0u8; 4];
if f.read_exact(&mut magic).is_err() { return false; }
// LLVM bitcode wrapper magic: 0xDE 0xC0 0x17 0x0B;
// raw bitcode: 'B' 'C' 0xC0 0xDE.
matches!(magic, [0xDE, 0xC0, 0x17, 0x0B] | [b'B', b'C', 0xC0, 0xDE])
}
// caller: assert!(lto_bitcode_file_readable(Path::new("foo.bc"))); Type guard
fn is_valid_lto_bitcode(path: &std::path::Path) -> bool {
lto_bitcode_file_readable(path)
} Try / catch
let stderr = String::from_utf8_lossy(&output.stderr);
if let Some(line) = stderr.lines().find(|l| l.contains("failed to open LTO bitcode file")) {
// Pull the path + OS error from the message, then either
// rebuild the bitcode (stale) or surface a missing-file error.
return Err(LinkError::BitcodeOpen(line.into()));
} Prevention
- Run `cargo clean` after toolchain upgrades to drop stale `.bc`/`.o` artifacts.
- Verify bitcode files exist and are readable before invoking LTO (`-C lto=fat|thin`).
- Pin `RUSTFLAGS=-C lto=off` when shipping to environments where bitcode files may be missing.
When it happens
Trigger: Reached during ThinLTO/fatLTO when rustc tries to load a serialized bitcode module file (path passed to from_file) that does not exist, has been deleted, or is unreadable. The file is expected to be present from a prior codegen/LTO serialization step.
Common situations: Incremental compilation cache (target/incremental) was deleted or corrupted between sessions. A killed/interrupted prior build left LTO metadata referencing a .bc file that was never fully written. Permissions or disk-full conditions during a prior run. Manual cleanup of target/ that removed only some LTO artifacts. Concurrent builds clobbering shared incremental state.
Related errors
- Error writing pre-lto-bitcode file `{}`: {}
- couldn't open rlib
- couldn't map rlib
- wanted an rlib
- corrupt rlib
AI-assisted analysis of rust-lang/rust@22057b88b0 (2026-08-03).
Data as JSON: /data/errors/583072560ae3ea01.json.
Report an issue: GitHub.