rust-lang/rust · error · anyhow::Error

opt failed optimize bitcode: {}

Error message

opt failed optimize bitcode: {}

What it means

Bailed by Session::optimize when the opt subprocess exits non-zero. opt runs the passes default<O>,internalize,globaldCE over the linked bitcode; failure indicates an invalid pass pipeline, an opt version that doesn't support the requested passes, or malformed input bitcode.

Source

Thrown at src/tools/llvm-bitcode-linker/src/linker.rs:122

            .arg(format!("--internalize-public-api-file={}", self.sym_path.display()))
            .arg(format!("--passes={}", passes));

        if !debug {
            opt_cmd.arg("--strip-debug");
        }

        let opt_output = opt_cmd.output().context(
            "An error occurred when calling opt. Make sure the llvm-tools component is installed.",
        )?;

        if !opt_output.status.success() {
            tracing::error!(
                "opt returned with Exit status: {}\n stdout: {}\n stderr: {}",
                opt_output.status,
                String::from_utf8(opt_output.stdout).unwrap(),
                String::from_utf8(opt_output.stderr).unwrap(),
            );
            anyhow::bail!("opt failed optimize bitcode: {}", self.link_path.display());
        };

        Ok(())
    }

    /// Compile the optimized bitcode file to native format using `llc`
    ///
    /// Before this can be called `optimize` needs to be called
    fn compile(&mut self) -> anyhow::Result<()> {
        let mut lcc_command = std::process::Command::new("llc");

        if let Some(mcpu) = &self.cpu {
            lcc_command.arg("--mcpu").arg(mcpu);
        }

        if let Some(mattr) = &self.feature {
            lcc_command.arg(&format!("--mattr={}", mattr));
        }

View on GitHub (pinned to 7088e4b63a)

Solutions

  1. Inspect the logged opt stderr for the exact pass/error.
  2. Ensure the opt on PATH is the same LLVM version as rustc's bundled LLVM (rustup component llvm-tools).
  3. Check that sym_path was written and contains one symbol per line.
  4. Re-run with a lower Optimization level to isolate pass-specific failures.

Example fix

// before
anyhow::bail!("opt failed optimize bitcode: {}", self.link_path.display());

// after: include opt's stderr so callers can act without reading logs
let stderr = String::from_utf8_lossy(&opt_output.stderr);
anyhow::bail!(
    "opt failed to optimize bitcode {} (passes={passes}): {}",
    self.link_path.display(),
    stderr.trim()
);
Defensive patterns

Strategy: validation

Validate before calling

// Ensure the opt binary matches rustc's LLVM and supports the passes:
fn opt_supports_passes(opt: &str, passes: &str) -> bool {
    let out = std::process::Command::new(opt).arg("--help-passes").output();
    matches!(out, Ok(o) if String::from_utf8_lossy(&o.stdout).contains(passes)))
}

Type guard

null

Try / catch

match session.lto(opt, debug) {
    Ok(()) => Ok(()),
    Err(e) if e.to_string().contains("opt failed") => {
        eprintln!("opt rejected the pass pipeline; check LLVM version alignment");
        Err(e)
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: Reached after a successful link(), when opt fails. Common when the opt binary is from a different LLVM than the one that produced the bitcode, or when the Optimization level is parsed into a value opt's default<> pipeline doesn't accept.

Common situations: PATH points at a system LLVM while rustc uses its bundled LLVM; an LLVM major-version bump renamed or removed a pass; the symbol file passed via --internalize-public-api-file is empty/malformed.

Related errors


AI-assisted analysis of rust-lang/rust@7088e4b63a (2026-08-10). Data as JSON: /api/errors/435e6c7bcab30a37. Report an issue: GitHub.