jdx/mise · error

artifact target has changed

Error message

artifact target has changed: {}

What it means

validate_cask_prune_candidate re-fingerprints every artifact target recorded in the cask receipt and refuses the prune if any target no longer matches its recorded fingerprint. This ensures the on-disk state is exactly what the install receipt captured before the prune mutates anything. A mismatch means something modified the artifact since installation and blindly pruning could destroy data or break the package.

Solutions

  1. Diff the target at record.path against the staged version copy; if the change is unwanted, restore the original before pruning.
  2. If the change is intentional user data, exclude that target from the prune plan or migrate the data first.
  3. Reinstall the cask to regenerate a consistent receipt and targets, then retry the prune.
Defensive patterns

Strategy: validation

Validate before calling

for record in &receipt.targets {
    if !cask_target_record_matches(record)? {
        eprintln!("target drifted: {}", record.path.display());
    }
}
// fix or exclude drifted targets before requesting a prune

Try / catch

match validate_cask_prune_candidate(&receipt, &candidate) {
    Err(e) if e.to_string().contains("artifact target has changed") => {
        // inspect/restore drifted targets, then retry
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling validate_cask_prune_candidate (via cask_prune_plan_from_tokens or apply_cask_prune_plan_in) when cask_target_record_matches returns false for any receipt.targets entry — i.e. the file/symlink at record.path changed kind, content, or link destination since the fingerprint was recorded.

Common situations: A user edited or replaced a binary/font/app target after install; a file-sync tool (Dropbox, git) modified the target; a partially failed upgrade left a target half-updated; the recorded path was overwritten by another package or a manual copy.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/6604b4da5841d09c. Report an issue: GitHub.

Appendix: source

Thrown at src/system/packages/brew/cask/state.rs:1140

    for path in &receipt.completions {
        let record = records
            .get(path)
            .ok_or_else(|| eyre!("missing completion target record"))?;
        if record.fingerprint.kind != CaskTargetKind::Symlink
            || !completion_roots
                .iter()
                .any(|root| path_is_below(path, root))
            || !symlink_resolves_below(path, &candidate.version_dir)
        {
            bail!(
                "completion target is not an owned Caskroom symlink: {}",
                path.display()
            );
        }
    }
    for record in &receipt.targets {
        if !cask_target_record_matches(record)? {
            bail!("artifact target has changed: {}", record.path.display());
        }
    }
    Ok(())
}

pub(super) fn path_is_below(path: &Path, root: &Path) -> bool {
    path.strip_prefix(root).is_ok_and(|relative| {
        relative.components().next().is_some()
            && !relative
                .components()
                .any(|component| component == Component::ParentDir)
    })
}

pub(super) fn staged_target_matches(record: &CaskTargetRecord, staged: &Path) -> bool {
    cask_target_fingerprint(staged).is_ok_and(|fingerprint| fingerprint == record.fingerprint)
}

View on GitHub (pinned to 533346cc37)