rust-lang/cargo · error · anyhow::Error

Source directory was modified by build.rs during cargo publi

Error message

Source directory was modified by build.rs during cargo publish. Build scripts should not modify anything outside of OUT_DIR.
{}

To proceed despite this, pass the `--no-verify` flag.

What it means

During `cargo publish` verification, Cargo hashes every file under the unpacked source before and after running the verification build. If the hashes differ it concludes a build script or proc-macro wrote outside of OUT_DIR (typically into src/), which would make the published crate non-deterministic. It bails at verify.rs:123 unless --no-verify is passed.

Source

Thrown at src/ops/cargo_package/verify.rs:123

            cli_features: opts.cli_features.clone(),
            spec: ops::Packages::Packages(Vec::new()),
            filter: ops::CompileFilter::Default {
                required_features_filterable: true,
            },
            target_rustdoc_args: None,
            target_rustc_args: rustc_args,
            target_rustc_crate_types: None,
            rustdoc_document_private_items: false,
            honor_rust_version: None,
        },
        &exec,
    )?;

    // Check that `build.rs` didn't modify any files in the `src` directory.
    let ws_fingerprint = hash_all(&dst)?;
    if pkg_fingerprint != ws_fingerprint {
        let changes = report_hash_difference(&pkg_fingerprint, &ws_fingerprint);
        anyhow::bail!(
            "Source directory was modified by build.rs during cargo publish. \
             Build scripts should not modify anything outside of OUT_DIR.\n\
             {}\n\n\
             To proceed despite this, pass the `--no-verify` flag.",
            changes
        )
    }

    Ok(())
}

/// Hashes everything under a given directory.
///
/// This is for checking if any source file inside a `.crate` file has changed
/// durint the compilation. It is usually caused by bad build scripts or proc
/// macros trying to modify source files. Cargo disallows that.
fn hash_all(path: &Path) -> CargoResult<HashMap<PathBuf, u64>> {
    fn wrap(path: &Path) -> CargoResult<HashMap<PathBuf, u64>> {

View on GitHub (pinned to 0e07a15537)

Solutions

  1. Fix the build script to write only to the OUT_DIR path passed via the environment variable, and include generated code via `include!(concat!(env!("OUT_DIR"), "/generated.rs"))`.
  2. If the modification is benign and you accept the risk, pass `--no-verify` to `cargo publish`.
  3. Audit proc-macros / build deps for any that write to the crate source tree.

Example fix

// before - build.rs writes into src/
fn main() {
    std::fs::write("src/generated.rs", "...").unwrap();
}

// after - write to OUT_DIR and include it
fn main() {
    let out = std::env::var("OUT_DIR").unwrap();
    std::fs::write(format!("{out}/generated.rs"), "...").unwrap();
}
// in lib.rs:
//   include!(concat!(env!("OUT_DIR"), "/generated.rs"));
Defensive patterns

Strategy: validation

Validate before calling

# Verify the source tree is unchanged after a local build:
before=$(find src -type f -exec sha256sum {} + | sha256sum)
cargo build
after=$(find src -type f -exec sha256sum {} + | sha256sum)
[ "$before" = "$after" ] || { echo "build.rs mutated src/"; exit 1; }

Prevention

When it happens

Trigger: A build.rs (or proc-macro invoked during the verify build) that writes/modifies files inside src/ or anywhere outside OUT_DIR; in-place code generators.

Common situations: Build scripts that patch source files; codegen tools that write into the crate source rather than emitting to OUT_DIR; accidental `include_str!`/codegen writing back to source.

Related errors


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