rust-lang/cargo · error

has_custom_build should have RunCustomBuild

Error message

has_custom_build should have RunCustomBuild

What it means

When a package has a custom build script (`unit.pkg.has_custom_build()`), Cargo fetches its link metadata via `find_build_script_metadatas(unit).expect("has_custom_build should have RunCustomBuild")`. The expect encodes the invariant that a package flagged as having a build script always has a corresponding `RunCustomBuild` unit whose metadata can be located. Failure means `has_custom_build()` and the unit/metadata bookkeeping disagree.

Source

Thrown at src/compiler/custom_build.rs:1320

            if let Some(links) = unit.pkg.manifest().links() {
                if let Some(output) = unit.links_overrides.get(links) {
                    let metadata = build_runner.get_run_build_script_metadata(unit);
                    build_runner.build_script_outputs.lock().unwrap().insert(
                        unit.pkg.package_id(),
                        metadata,
                        output.clone(),
                    );
                }
            }
        }

        let mut ret = BuildScripts::default();

        // If a package has a build script, add itself as something to inspect for linking.
        if !unit.target.is_custom_build() && unit.pkg.has_custom_build() {
            let script_metas = build_runner
                .find_build_script_metadatas(unit)
                .expect("has_custom_build should have RunCustomBuild");
            for script_meta in script_metas {
                add_to_link(&mut ret, unit.pkg.package_id(), script_meta);
            }
        }

        if unit.mode.is_run_custom_build() {
            parse_previous_explicit_deps(build_runner, unit);
        }

        // We want to invoke the compiler deterministically to be cache-friendly
        // to rustc invocation caching schemes, so be sure to generate the same
        // set of build script dependency orderings via sorting the targets that
        // come out of the `Context`.
        let mut dependencies: Vec<Unit> = build_runner
            .unit_deps(unit)
            .iter()
            .map(|d| d.unit.clone())
            .collect();

View on GitHub (pinned to 0e07a15537)

Solutions

  1. `cargo clean` and rebuild to regenerate build-script metadata.
  2. Ensure only one Cargo version operates on a given `target/` dir.
  3. If reproducible, report upstream with the minimal `Cargo.toml` that has a `build.rs`.

Example fix

// before
let script_metas = build_runner
    .find_build_script_metadatas(unit)
    .expect("has_custom_build should have RunCustomBuild");
// after
let script_metas = build_runner
    .find_build_script_metadatas(unit)
    .with_context(|| format!("package `{}` flagged has_custom_build but its RunCustomBuild metadata is missing", unit.pkg.package_id()))?;
Defensive patterns

Strategy: validation

Validate before calling

// (cargo-internal) before reading link metadata, confirm a RunCustomBuild unit exists for the pkg:
// assert!(build_runner.unit_graph.iter().any(|(u, _)| u.pkg == unit.pkg && u.mode.is_run_custom_build()));

Prevention

When it happens

Trigger: A package whose `Cargo.toml` declares `build = ...` (so `has_custom_build` is true) but whose unit graph lacks the `RunCustomBuild` unit, or whose `find_build_script_metadatas` returns `Err`; inconsistent state between `Package` metadata and the compiled build-script outputs.

Common situations: Interrupted build leaving `target/` with stale metadata; Cargo version mismatch between who wrote `target/` and who is reading it; metabuild/`build.rs` rename without `cargo clean`.

Related errors


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