rust-lang/cargo · error
build script logged errors
Error message
build script logged errors
What it means
Cargo runs a package's build.rs and streams its stdout. Any line beginning with 'cargo::error=' (legacy 'cargo:error=' unsupported, but warnings use 'cargo:warning='/'cargo::warning=') is recorded at Severity::Error. Even when the build script exits successfully (exit code 0), if at least one cargo::error= line was logged, Cargo treats the unit as failed (custom_build.rs:660-672) and bails with 'build script logged errors'. This lets build scripts emit structured errors without a non-zero exit.
Source
Thrown at src/compiler/custom_build.rs:671
build_script_outputs,
id,
metadata_hash,
log_messages_in_case_of_panic,
);
return Err(error);
}
// ... or it logged any errors
else if log_messages_in_case_of_panic
.iter()
.any(|(severity, _)| *severity == Severity::Error)
{
insert_log_messages_in_build_outputs(
build_script_outputs,
id,
metadata_hash,
log_messages_in_case_of_panic,
);
anyhow::bail!("build script logged errors");
}
let output = output.unwrap();
// After the build command has finished running, we need to be sure to
// remember all of its output so we can later discover precisely what it
// was, even if we don't run the build command again (due to freshness).
//
// This is also the location where we provide feedback into the build
// state informing what variables were discovered via our script as
// well.
paths::write(&run_files.stdout, &output.stdout)?;
// This mtime shift allows Cargo to detect if a source file was
// modified in the middle of the build.
paths::set_file_time_no_err(run_files.stdout, timestamp);
paths::write(&run_files.stderr, &output.stderr)?;
paths::write(&run_files.root_output, paths::path2bytes(&script_out_dir)?)?;
let parsed_output = BuildOutput::parse(View on GitHub (pinned to 0e07a15537)
Solutions
- Re-run with `cargo build -vv` (extra_verbose) to surface the exact 'cargo::error=' message the script printed.
- Open the failing package's build.rs and find the `cargo::error=` emission; fix the underlying condition (install the missing system lib, set the env var, etc.).
- If the error emission was unintended, change `cargo::error=` to `cargo::warning=` so it no longer fails the build, or remove the line.
- Ensure the script exits non-zero on real failure instead of relying solely on cargo::error= if you want explicit exit codes.
Example fix
// before (build.rs)
println!("cargo::error=libfoo not found");
// after
println!("cargo:warning=libfoo not found, using fallback"); Defensive patterns
Strategy: validation
Validate before calling
// In build.rs, gate any cargo::error= emission behind a real check and
// prefer cargo:warning= for non-fatal conditions.
fn require_tool(name: &str) {
if !std::process::Command::new(name).output().is_ok() {
println!("cargo::warning={name} not found"); // not cargo::error=
}
} Prevention
- Run builds with -vv during development to see every cargo::error=/cargo:warning= line.
- Reserve cargo::error= for conditions that should always fail the build; exit non-zero for hard failures.
- Audit dependency build scripts when upgrading crates that bind native libraries.
When it happens
Trigger: A build.rs prints a line like `println!("cargo::error=some message")` (or code that does) and then exits 0. The streaming callback in exec_with_streaming pushes (Severity::Error, msg); the post-run check sees it and bails.
Common situations: Build script that conditionally emits cargo::error= for a missing system dependency but forgets to exit non-zero; a dependency's build script emitting cargo::error=; migrating from cargo:warning= to cargo::error= to harden a previously-soft check.
Related errors
- `{}` is not supported in build script overrides
- {}This may cause issue during packaging, as modules resoluti
- previously normalized
AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06).
Data as JSON: /data/errors/034ba5c597aaa8bf.json.
Report an issue: GitHub.