rust-lang/cargo · error
output must exist after running
Error message
output must exist after running
What it means
After a build script runs, the fingerprint job reads its captured stdout via `build_script_outputs.get(metadata).expect("output must exist after running")`. Cargo inserts the build script's parsed output into the shared `build_script_outputs` map at the moment it finishes; the fingerprint job runs only after that insert. The panic means the metadata key was absent — the script's output was never recorded, was overwritten/removed, or a different metadata value was used.
Source
Thrown at src/compiler/fingerprint/mod.rs:568
// while we're executing it. For example it could be in the legacy
// "consider everything a dependency mode" and then we switch to "deps
// are explicitly specified" mode.
//
// To handle this movement we need to regenerate the `local` field of a
// build script's fingerprint after it's executed. We do this by
// using the `build_script_local_fingerprints` function which returns a
// thunk we can invoke on a foreign thread to calculate this.
let build_script_outputs = Arc::clone(&build_runner.build_script_outputs);
let metadata = build_runner.get_run_build_script_metadata(unit);
let (gen_local, _overridden) = build_script_local_fingerprints(build_runner, unit)?;
let output_path = build_runner.build_explicit_deps[unit]
.build_script_output
.clone();
Work::new(move |_| {
let outputs = build_script_outputs.lock().unwrap();
let output = outputs
.get(metadata)
.expect("output must exist after running");
let deps = BuildDeps::new(&output_path, Some(output));
// FIXME: it's basically buggy that we pass `None` to `call_box`
// here. See documentation on `build_script_local_fingerprints`
// below for more information. Despite this just try to proceed and
// hobble along if it happens to return `Some`.
if let Some(new_local) = (gen_local)(&deps, None)? {
*fingerprint.local.lock().unwrap() = new_local;
}
write_fingerprint(&loc, &fingerprint)
})
} else {
Work::new(move |_| write_fingerprint(&loc, &fingerprint))
};
Ok(Job::new_dirty(write_fingerprint, dirty_reason))
}View on GitHub (pinned to 0e07a15537)
Solutions
- Re-run the build; transient kills/timing races usually clear on retry.
- Inspect whether the build script itself failed (`cargo build -vv`) — fix the script first.
- `cargo clean` to remove stale state, then rebuild.
- Avoid running multiple Cargo invocations against the same `target/` simultaneously.
Example fix
// before
let output = outputs
.get(metadata)
.expect("output must exist after running");
// after
let output = outputs.get(metadata).ok_or_else(|| {
anyhow::anyhow!("build script output for metadata `{:?}` was not recorded; did the script fail to run?", metadata)
})?; Defensive patterns
Strategy: retry
Validate before calling
// Before the build, sanity-check that build scripts in your dependency tree succeed standalone: // `cargo build -vv 2>&1 | grep 'error'` to surface build-script failures early.
Try / catch
// Retry the build once; transient races usually clear
for attempt in 0..2 {
let s = std::process::Command::new("cargo").arg("build").status()?;
if s.success() { break; }
if attempt == 1 { return Err(s.into()); }
std::thread::sleep(std::time::Duration::from_secs(1));
} Prevention
- Fix build scripts that exit non-zero before relying on their outputs.
- Avoid running multiple Cargo builds against the same `target/` simultaneously.
- Don't `cargo clean` while a build is in progress.
When it happens
Trigger: A build script panic/error that prevented its output from being inserted yet still scheduled the fingerprint job; the metadata object compared by a key that mutated between insert and lookup; concurrent cleanup wiping the map; Cargo bug in dependency-metadata passing for foreign-thread fingerprint calculation.
Common situations: Build script that exits non-zero or is killed mid-run; concurrent `cargo clean`; long-lived Cargo-as-library process whose `build_script_outputs` was cleared; thread-safety regression in the shared `Mutex<HashMap>`.
Related errors
- running a script not depending on an actual script
- has_custom_build should have RunCustomBuild
- failed to find rmeta
- artifact-dir was not locked
- required(true)
AI-assisted analysis of rust-lang/cargo@0e07a15537 (2026-08-06).
Data as JSON: /data/errors/ba1cd685f4b024c3.json.
Report an issue: GitHub.