rust-lang/cargo · error

artifact-dir was not locked

Error message

artifact-dir was not locked

What it means

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.

Source

Thrown at src/compiler/fingerprint/rustdoc.rs:246

                    on_disk_fingerprint.rustc_vv,
                    new_fingerprint.rustc_vv
                );
            }
        }
        Err(e) => {
            tracing::debug!("could not deserialize {:?}: {}", fingerprint_path, e);
        }
    };
    // Fingerprint does not match, delete the doc directories and write a new fingerprint.
    tracing::debug!(
        "fingerprint {:?} mismatch, clearing doc directories",
        fingerprint_path
    );
    let doc_dir = build_runner
        .files()
        .layout(kind)
        .artifact_dir()
        .expect("artifact-dir was not locked")
        .doc();
    if doc_dir.exists() {
        clean_doc(doc_dir)?;
    }

    write_fingerprint()?;

    Ok(())
}

/// Loads an on-disk fingerprint JSON file.
fn load_on_disk(path: &Path) -> Option<RustdocFingerprintJson> {
    let on_disk = match paths::read(path) {
        Ok(data) => data,
        Err(e) => {
            tracing::debug!("failed to read rustdoc fingerprint at {path:?}: {e}");
            return None;
        }

View on GitHub (pinned to 0e07a15537)

Solutions

  1. `cargo clean --doc` (or full `cargo clean`) to remove the stale rustdoc fingerprint and let it rebuild.
  2. Run a single `cargo doc` at a time per target dir.
  3. Drop unstable doc/layout flags and retry.

Example fix

// before
let doc_dir = build_runner
    .files()
    .layout(kind)
    .artifact_dir()
    .expect("artifact-dir was not locked")
    .doc();
// after
let doc_dir = build_runner
    .files()
    .layout(kind)
    .artifact_dir()
    .ok_or_else(|| anyhow::anyhow!("rustdoc fingerprint refresh: artifact dir for kind `{:?}` was not locked", kind))?
    .doc();
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the rustdoc fingerprint dir is intact before `cargo doc`
fn doc_fingerprint_intact(target: &std::path::Path) -> bool {
    target.join(".rustdoc_fingerprint.json").exists() || true // absence just triggers a rebuild
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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