{"record":{"id":"4d571bcf1d0ce156","repo":"rust-lang/cargo","slug":"artifact-dir-was-not-locked-during-clean","errorCode":null,"errorMessage":"artifact-dir was not locked during clean","messagePattern":"artifact-dir was not locked during clean","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/ops/cargo_clean.rs","lineNumber":307,"sourceCode":"            // Remove the uplifted copy.\n            for target in pkg.targets() {\n                if target.is_custom_build() {\n                    continue;\n                }\n                let crate_name: Rc<str> = target.crate_name().into();\n                for &mode in &[\n                    CompileMode::Build,\n                    CompileMode::Test,\n                    CompileMode::Check { test: false },\n                ] {\n                    for (compile_kind, layout) in &layouts {\n                        let triple = target_data.short_name(compile_kind);\n                        let (file_types, _unsupported) = target_data\n                            .info(*compile_kind)\n                            .rustc_outputs(mode, target.kind(), triple)?;\n                        let artifact_dir = layout\n                            .artifact_dir()\n                            .expect(\"artifact-dir was not locked during clean\");\n                        let uplift_dir = match target.kind() {\n                            TargetKind::ExampleBin | TargetKind::ExampleLib(..) => {\n                                Some(artifact_dir.examples())\n                            }\n                            // Tests/benchmarks are never uplifted.\n                            TargetKind::Test | TargetKind::Bench => None,\n                            _ => Some(artifact_dir.dest()),\n                        };\n                        if let Some(uplift_dir) = uplift_dir {\n                            for file_type in file_types {\n                                let uplifted_filename = file_type.uplift_filename(target);\n\n                                // Dep-info generated by Cargo itself.\n                                let dep_info = Path::new(&uplifted_filename)\n                                    .with_extension(\"d\")\n                                    .to_string_lossy()\n                                    .into_owned();\n","sourceCodeStart":289,"sourceCodeEnd":325,"githubUrl":"https://github.com/rust-lang/cargo/blob/98a09e7e7d62850f14e5b6132101fc1edd19a16f/src/ops/cargo_clean.rs#L289-L325","documentation":"This is an internal Cargo invariant assertion (panic) in `clean_packages` (src/ops/cargo_clean.rs), reached while computing which uplifted artifact files to delete for each package target. `Layout::artifact_dir()` returns `Option` because Cargo only populates it when the layout was created with `must_take_artifact_dir_lock = true` (src/compiler/layout.rs:294-318); `cargo clean` always constructs its layouts with that flag set (cargo_clean.rs:200,206), so the expect firing means Cargo's own invariant broke — i.e., a Cargo bug, most plausibly in the `-Zbuild-dir-new-layout` code path that guards this block (cargo_clean.rs:278), not anything in your project.","triggerScenarios":"Running `cargo clean` (optionally `-p <pkg>`) on a nightly toolchain with `-Z build-dir-new-layout` enabled (via CLI flag, `CARGO_UNSTABLE_BUILD_DIR_NEW_LAYOUT=1`, or an `[unstable]` config table), where a code regression or a layout constructed without the artifact-dir lock reaches the per-target uplift-removal loop at lines 299-306. Not reachable through normal user configuration of a released stable cargo.","commonSituations":"Nightly users experimenting with the build-directory re-layout migration sharing one `target/` dir across several cargo versions; cargo built from source or patched; IDE-embedded cargo (rust-analyzer) invoking a mismatched cargo on a workspace created by a different version; interrupted cleans leaving lock state half-updated.","solutions":["Bypass cargo entirely: `rm -rf target` (or `cargo +stable clean`) removes the same directories without hitting the buggy path.","Stop enabling the experimental flag: drop `-Zbuild-dir-new-layout` / `build-dir-new-layout` from your invocation, `CARGO_UNSTABLE_*` env, or `.cargo/config.toml` `[unstable]` table, then retry `cargo clean`.","Update the nightly (`rustup update nightly`) — invariants like this are usually fixed quickly during the migration — and retest in a scratch copy of the workspace.","If it still reproduces, report it to https://github.com/rust-lang/cargo/issues including `cargo +nightly version --verbose`, the exact command, and whether multiple cargo versions share the target dir."],"exampleFix":"# before: panics with `artifact-dir was not locked during clean`\ncargo +nightly -Zbuild-dir-new-layout clean\n\n# after: same effect, no buggy code path\nrm -rf target\n# or\ncargo +stable clean","handlingStrategy":"fallback","validationCode":"# Guard scripts: refuse `cargo clean` while the experimental layout flag is on\nif cargo +nightly -Zhelp 2>/dev/null | grep -q build-dir-new-layout \\\n   && grep -RqsE 'build-dir-new-layout|min-publish-age' .cargo/config.toml ~/.cargo/config.toml; then\n  echo \"unstable flags present — falling back to rm -rf target\"\n  rm -rf target\nelse\n  cargo clean\nfi","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Give each cargo/toolchain version its own target directory (e.g. per-toolchain CARGO_TARGET_DIR in CI) instead of sharing one target/ across versions.","Run `cargo clean` with the same toolchain that produced the artifacts; add `rust-toolchain.toml` so every invocation, including IDEs, agrees.","In scripts, prefer `rm -rf target` as the documented fallback when `cargo clean` exits non-zero or panics.","Keep nightlies current (`rustup update`) when opting into `-Z` flags — these invariants move fast during migrations.","Wrap CI clean steps with `set +e` on the clean command and a manual directory removal fallback so a clean panic cannot fail unrelated jobs."],"tags":["rust","cargo","cargo-clean","panic","internal-assertion","nightly","build-dir-new-layout"],"backgroundTag":"internal-assertion-panic","analyzedSha":"98a09e7e7d62850f14e5b6132101fc1edd19a16f","analyzedAt":"2026-08-21T19:15:00.589Z","contentChangedAt":"2026-08-21T19:15:00.589Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}