rust-lang/rust · error · anyhow::Error
llvm-link failed to link files {:?}
Error message
llvm-link failed to link files {:?} What it means
Bailed by Session::link when the external llvm-link process exits with a non-zero status. The tool invokes llvm-link --ignore-non-bitcode over all added files; failure means LLVM could not merge the bitcode (corrupt input, incompatible modules, unresolved symbols). The detailed stdout/stderr is logged at error level before the bail.
Source
Thrown at src/tools/llvm-bitcode-linker/src/linker.rs:80
fn link(&mut self) -> anyhow::Result<()> {
tracing::info!("Linking {} files using llvm-link", self.files.len());
let llvm_link_output = std::process::Command::new("llvm-link")
.arg("--ignore-non-bitcode")
.args(&self.files)
.arg("-o")
.arg(&self.link_path)
.output()
.context("An error occurred when calling llvm-link. Make sure the llvm-tools component is installed.")?;
if !llvm_link_output.status.success() {
tracing::error!(
"llvm-link returned with Exit status: {}\n stdout: {}\n stderr: {}",
llvm_link_output.status,
String::from_utf8(llvm_link_output.stdout).unwrap(),
String::from_utf8(llvm_link_output.stderr).unwrap(),
);
anyhow::bail!("llvm-link failed to link files {:?}", self.files);
}
Ok(())
}
/// Optimize and compile to native format using `opt` and `llc`
///
/// Before this can be called `link` needs to be called
fn optimize(&mut self, optimization: Optimization, debug: bool) -> anyhow::Result<()> {
let mut passes = format!("default<{}>", optimization);
// We add an internalize pass as the rust compiler as we require exported symbols to be explicitly marked
passes.push_str(",internalize,globaldce");
let symbol_file_content = self.symbols.iter().fold(String::new(), |s, x| s + &x + "\n");
std::fs::write(&self.sym_path, symbol_file_content)
.context(format!("Failed to write symbol file: {}", self.sym_path.display()))?;
tracing::info!("optimizing bitcode with passes: {}", passes);View on GitHub (pinned to 7088e4b63a)
Solutions
- Check the tracing error logs for llvm-link's stderr — it names the offending file and reason.
- Rebuild all input rlibs/bitcode with the same toolchain so their LLVM versions match.
- Verify each input is valid bitcode: llvm-dis <file> -o - | head, or llvm-bcanalyzer <file>.
- Ensure the llvm-tools/llvm-link component is installed and on PATH and matches the rustc LLVM.
Example fix
// before: generic message, logs only on tracing channel
anyhow::bail!("llvm-link failed to link files {:?}", self.files);
// after: include captured stderr in the error for the caller
let stderr = String::from_utf8_lossy(&llvm_link_output.stderr);
anyhow::bail!(
"llvm-link failed to link {} files: {}",
self.files.len(),
stderr.trim()
); Defensive patterns
Strategy: validation
Validate before calling
// Before linking, verify every input is bitcode the matching LLVM accepts:
use std::process::Command;
fn all_valid_bitcode(files: &[PathBuf], llvm_link: &str) -> bool {
files.iter().all(|f| Command::new(llvm_link)
.arg("--check").arg(f).output().map(|o| o.status.success()).unwrap_or(false))
} Type guard
null
Try / catch
// Surface llvm-link stderr to the caller instead of swallowing it:
match session.lto(opt, debug) {
Ok(()) => Ok(()),
Err(e) if e.to_string().contains("llvm-link failed") => {
eprintln!("llvm-link rejected an input; ensure all bitcode is from the same LLVM");
Err(e)
}
Err(e) => Err(e),
} Prevention
- Always build rlibs/bitcode inputs with the same rustc/LLVM as the linker.
- Keep llvm-tools (llvm-link) on PATH and version-matched to rustc.
- Validate inputs with llvm-bcanalyzer before linking.
When it happens
Trigger: Calling Session::lto (or link directly) after add_file with one or more bitcode/archive files, when llvm-link returns non-zero. Caused by: a non-bitcode file that --ignore-non-bitcode still rejects, mismatched LLVM bitcode versions across inputs, duplicate module definitions, or a corrupt .bc file.
Common situations: Mixing rlibs/bitcode produced by different rustc versions; passing an archive that contains no valid bitcode member; an LLVM upgrade that changed the bitcode format; running without the llvm-tools component (though that path fails earlier with the context message).
Related errors
- opt failed optimize bitcode: {}
- llc failed to compile {} into {}
- llvm-readelf failed for binary {binary} with output {stdout}
- Build ID not found for binary {binary}
- unexpected base kind for gap region: {kind:?}
AI-assisted analysis of rust-lang/rust@7088e4b63a (2026-08-10).
Data as JSON: /api/errors/f1909dae93f82204.
Report an issue: GitHub.