{"id":"e1436b4fb2922297","repo":"rust-lang/cargo","slug":"artifact-dir-was-not-locked-e1436b","errorCode":null,"errorMessage":"artifact-dir was not locked","messagePattern":"artifact-dir was not locked","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/compiler/fingerprint/rustdoc.rs","lineNumber":246,"sourceCode":"                    on_disk_fingerprint.rustc_vv,\n                    new_fingerprint.rustc_vv\n                );\n            }\n        }\n        Err(e) => {\n            tracing::debug!(\"could not deserialize {:?}: {}\", fingerprint_path, e);\n        }\n    };\n    // Fingerprint does not match, delete the doc directories and write a new fingerprint.\n    tracing::debug!(\n        \"fingerprint {:?} mismatch, clearing doc directories\",\n        fingerprint_path\n    );\n    let doc_dir = build_runner\n        .files()\n        .layout(kind)\n        .artifact_dir()\n        .expect(\"artifact-dir was not locked\")\n        .doc();\n    if doc_dir.exists() {\n        clean_doc(doc_dir)?;\n    }\n\n    write_fingerprint()?;\n\n    Ok(())\n}\n\n/// Loads an on-disk fingerprint JSON file.\nfn load_on_disk(path: &Path) -> Option<RustdocFingerprintJson> {\n    let on_disk = match paths::read(path) {\n        Ok(data) => data,\n        Err(e) => {\n            tracing::debug!(\"failed to read rustdoc fingerprint at {path:?}: {e}\");\n            return None;\n        }","sourceCodeStart":228,"sourceCodeEnd":264,"githubUrl":"https://github.com/rust-lang/cargo/blob/0e07a155371a6ce88ae53a2c00df940280c09a67/src/compiler/fingerprint/rustdoc.rs#L228-L264","documentation":"In the rustdoc fingerprint path, when a fingerprint mismatch is detected Cargo clears the doc directory via `layout(kind).artifact_dir().expect(\"artifact-dir was not locked\")` — the same invariant as in `CompilationFiles::output_dir`. The doc layout's artifact dir must have been acquired; `None` means a doc fingerprint refresh is running against a layout that was never locked, an internal inconsistency.","triggerScenarios":"Running `cargo doc` and hitting a rustdoc fingerprint mismatch (e.g. after a Cargo/rustdoc version change) on a code path where the artifact dir was not prepared; concurrent `cargo clean` removing the layout's lock files; a profile/flag combination that skips artifact-dir preparation but still runs the rustdoc fingerprint check.","commonSituations":"Switching rustdoc versions across `cargo doc` runs without `cargo clean`; multiple `cargo doc` invocations on the same target dir; unstable doc flags altering layout preparation.","solutions":["`cargo clean --doc` (or full `cargo clean`) to remove the stale rustdoc fingerprint and let it rebuild.","Run a single `cargo doc` at a time per target dir.","Drop unstable doc/layout flags and retry."],"exampleFix":"// before\nlet doc_dir = build_runner\n    .files()\n    .layout(kind)\n    .artifact_dir()\n    .expect(\"artifact-dir was not locked\")\n    .doc();\n// after\nlet doc_dir = build_runner\n    .files()\n    .layout(kind)\n    .artifact_dir()\n    .ok_or_else(|| anyhow::anyhow!(\"rustdoc fingerprint refresh: artifact dir for kind `{:?}` was not locked\", kind))?\n    .doc();","handlingStrategy":"validation","validationCode":"// Confirm the rustdoc fingerprint dir is intact before `cargo doc`\nfn doc_fingerprint_intact(target: &std::path::Path) -> bool {\n    target.join(\".rustdoc_fingerprint.json\").exists() || true // absence just triggers a rebuild\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run `cargo clean --doc` after switching rustdoc versions.","Run a single `cargo doc` per target dir at a time.","Drop unstable doc/layout flags if you see this recurrently."],"tags":["cargo","rustdoc","fingerprint","layout","internal-invariant"],"analyzedSha":"0e07a155371a6ce88ae53a2c00df940280c09a67","analyzedAt":"2026-08-06T01:46:58.334Z","schemaVersion":2}