rust-lang/cargo · error
Source directory was modified by build.rs during cargo…
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
Thrown during the verification step of `cargo publish` when a build script (`build.rs`) modifies files inside the `src` directory. Cargo fingerprints the source tree before and after compilation; a hash mismatch means the build script wrote outside its designated `OUT_DIR`, which could corrupt the published crate. The `--no-verify` flag skips this check.
Solutions
- Fix the build script to write generated files exclusively to `$OUT_DIR` (the directory passed to build scripts).
- Fix proc macros to not emit files into the source tree.
- Pass `--no-verify` to bypass the check if the modification is intentional and safe: `cargo publish --no-verify`.
Example fix
// build.rs (before — writes to src/)
fn main() {
std::fs::write("src/generated.rs", "// ...").unwrap();
}
// build.rs (after — writes to OUT_DIR)
fn main() {
let out_dir = std::env::var("OUT_DIR").unwrap();
std::fs::write(
std::path::Path::new(&out_dir).join("generated.rs"),
"// ...",
).unwrap();
} Defensive patterns
Strategy: validation
Validate before calling
// Verify build script only writes to OUT_DIR
// In build.rs, always use:
fn main() {
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR not set");
// Only write under out_dir
let path = std::path::Path::new(&out_dir).join("generated.rs");
std::fs::write(&path, "// generated").unwrap();
println!("cargo:rerun-if-changed=some_input.txt");
} Prevention
- Never write to `src/` or any path outside `OUT_DIR` in build scripts.
- Audit proc macros for file-writing side effects.
- Run `cargo publish --dry-run` locally which triggers the verification step.
When it happens
Trigger: Running `cargo publish` (without `--no-verify`) on a crate whose `build.rs` or a proc-macro invoked during compilation writes to, creates, or deletes files under `src/`. The `hash_all(&dst)` comparison detects any change.
Common situations: Build scripts that generate code into `src/` instead of `OUT_DIR`; proc macros that emit files next to source; buggy or malicious build scripts; code generators writing to tracked source paths.
Related errors
- all dependencies must have a version requirement specified…
- build script logged errors
- cannot specify both `metabuild` and `build`
- found build scripts with duplicate file stems, but all…
- invalid `package.build` file name
AI-assisted analysis of rust-lang/cargo@eb98b54bc9 (2026-08-11).
Data as JSON: /api/errors/76ec12e7f02df424.
Report an issue: GitHub.
Appendix: 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 eb98b54bc9)