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

  1. Run cargo clean and rebuild so all LTO bitcode is regenerated consistently.
  2. Ensure the build is not interrupted mid-LTO and that target/ is not partially deleted between runs.
  3. Check available disk space and write permissions on the target directory; LTO bitcode files are large.
  4. 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

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


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