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

  1. Re-run with `cargo build -vv` (extra_verbose) to surface the exact 'cargo::error=' message the script printed.
  2. 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.).
  3. If the error emission was unintended, change `cargo::error=` to `cargo::warning=` so it no longer fails the build, or remove the line.
  4. 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

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


AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06). Data as JSON: /data/errors/034ba5c597aaa8bf.json. Report an issue: GitHub.