rust-lang/rust · error

Error writing pre-lto-bitcode file `{}`: {}

Error message

Error writing pre-lto-bitcode file `{}`: {}

What it means

Raised in the Thin-LTO branch of execute_optimize_work_item when rustc has just serialized a module to a thin bitcode buffer and fails to persist it to the incremental-compilation session directory. The panic happens in fs::write to a path computed from incr_comp_session_dir joined with pre_lto_bitcode_filename(module.name). It indicates an I/O failure writing the pre-LTO .bc artifact that downstream Thin-LTO steps will need to read back.

Source

Thrown at compiler/rustc_codegen_ssa/src/back/write.rs:859

    // If we're doing some form of incremental LTO then we need to be sure to
    // save our module to disk first.
    let bitcode = if cgcx.module_config.emit_pre_lto_bc {
        let filename = pre_lto_bitcode_filename(&module.name);
        cgcx.incr_comp_session_dir.as_ref().map(|path| path.join(&filename))
    } else {
        None
    };

    match lto_type {
        ComputedLtoType::No => {
            let module = B::codegen(cgcx, &prof, &shared_emitter, module, &cgcx.module_config);
            WorkItemResult::Finished(module)
        }
        ComputedLtoType::Thin => {
            let thin_buffer = B::serialize_module(module.module_llvm, true);
            if let Some(path) = bitcode {
                fs::write(&path, thin_buffer.data()).unwrap_or_else(|e| {
                    panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e);
                });
            }
            WorkItemResult::NeedsThinLto(module.name, thin_buffer)
        }
        ComputedLtoType::Fat => match bitcode {
            Some(path) => {
                let buffer = B::serialize_module(module.module_llvm, false);
                fs::write(&path, buffer.data()).unwrap_or_else(|e| {
                    panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e);
                });
                WorkItemResult::NeedsFatLto(FatLtoInput::Serialized {
                    name: module.name,
                    bitcode_path: path,
                })
            }
            None => WorkItemResult::NeedsFatLto(FatLtoInput::InMemory(module)),
        },
    }

View on GitHub (pinned to 22057b88b0)

Solutions

  1. Free disk space and inodes on the volume holding target/
  2. Stop concurrent processes touching target/incremental (e.g. another cargo invocation or a cleaner)
  3. Move target to a local non-network directory: CARGO_TARGET_DIR=/local/target
  4. Disable incremental compilation if the env is hostile: CARGO_INCREMENTAL=0
  5. On Windows, exclude the target dir from antivirus scanning

Example fix

# before (disk full / shared FS)
CARGO_INCREMENTAL=1 cargo build
# after
CARGO_INCREMENTAL=0 cargo build
Defensive patterns

Strategy: try-catch

Validate before calling

use std::path::{Path, PathBuf};
use std::fs;

fn preflight_write_pre_lto(path: &Path) -> std::io::Result<()> {
    if let Some(parent) = path.parent() {
        if !parent.as_os_str().is_empty() && !parent.exists() {
            fs::create_dir_all(parent)?;
        }
        // probe writability without committing the real file
        let probe = parent.join(format!(".{}.writeprobe", path.file_name().and_then(|s| s.to_str()).unwrap_or("tmp")));
        fs::write(&probe, b"")?;
        fs::remove_file(&probe)?;
    }
    if path.exists() && fs::metadata(path)?.permissions().readonly() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::PermissionDenied,
            "pre-lto-bitcode target is read-only",
        ));
    }
    let free = fs2::free_space(path.parent().unwrap_or(Path::new(".")))
        .ok();
    if let Some(b) = free {
        if b < 256 * 1024 * 1024 {
            return Err(std::io::Error::new(
                std::io::ErrorKind::Other,
                "insufficient free space for pre-lto-bitcode write",
            ));
        }
    }
    Ok(())
}

// before invoking codegen: preflight_write_pre_lto(&out_path)?;

Type guard

// Write errors here are thin wrappers around std::io::Error; narrow on kind.
fn is_pre_lto_write_error(e: &std::io::Error) -> bool {
    matches!(
        e.kind(),
        std::io::ErrorKind::PermissionDenied
            | std::io::ErrorKind::NotFound
            | std::io::ErrorKind::StorageFull
            | std::io::ErrorKind::ReadOnlyFilesystem
            | std::io::ErrorKind::QuotaExceeded
    )
}

Try / catch

match write_pre_lto_bitcode(&path, &bitcode) {
    Ok(()) => {},
    Err(ref e) if e.kind() == std::io::ErrorKind::StorageFull
               || e.kind() == std::io::ErrorKind::QuotaExceeded => {
        // non-retryable resource exhaustion; surface to caller, do NOT silently drop
        return Err(format!("disk/quota full writing {}: {}", path.display(), e).into());
    }
    Err(ref e) if e.kind() == std::io::ErrorKind::PermissionDenied
               || e.kind() == std::io::ErrorKind::ReadOnlyFilesystem => {
        return Err(format!("permission denied writing {}: {}", path.display(), e).into());
    }
    Err(ref e) if e.kind() == std::io::ErrorKind::Interrupted => {
        // single bounded retry; Interrupted is explicitly documented as retryable
        write_pre_lto_bitcode(&path, &bitcode)
            .map_err(|e| format!("retry failed writing {}: {}", path.display(), e))?;
    }
    Err(e) => return Err(format!("error writing pre-lto-bitcode {}: {}", path.display(), e).into()),
}

Prevention

When it happens

Trigger: cgcx.module_config.emit_pre_lto_bc is true (incremental + Thin LTO), lto_type is ComputedLtoType::Thin, and fs::write(&path, thin_buffer.data()) returns Err. Concrete causes: target/incremental dir deleted or moved mid-build, disk full, out of inodes, path on a read-only mount, antivirus locking the file on Windows, or a permission drop between rustc spawns.

Common situations: CI disk pressure; cleaning target/ while a build runs; building into an NFS/SMB share; Windows Defender scanning .bc files; cargo workspace where one member wipes the shared target dir; out-of-space on small cloud VMs.

Related errors


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