{"record":{"id":"6604b4da5841d09c","repo":"jdx/mise","slug":"artifact-target-has-changed-6604b4","errorCode":null,"errorMessage":"artifact target has changed: {}","messagePattern":"artifact target has changed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/state.rs","lineNumber":1140,"sourceCode":"    for path in &receipt.completions {\n        let record = records\n            .get(path)\n            .ok_or_else(|| eyre!(\"missing completion target record\"))?;\n        if record.fingerprint.kind != CaskTargetKind::Symlink\n            || !completion_roots\n                .iter()\n                .any(|root| path_is_below(path, root))\n            || !symlink_resolves_below(path, &candidate.version_dir)\n        {\n            bail!(\n                \"completion target is not an owned Caskroom symlink: {}\",\n                path.display()\n            );\n        }\n    }\n    for record in &receipt.targets {\n        if !cask_target_record_matches(record)? {\n            bail!(\"artifact target has changed: {}\", record.path.display());\n        }\n    }\n    Ok(())\n}\n\npub(super) fn path_is_below(path: &Path, root: &Path) -> bool {\n    path.strip_prefix(root).is_ok_and(|relative| {\n        relative.components().next().is_some()\n            && !relative\n                .components()\n                .any(|component| component == Component::ParentDir)\n    })\n}\n\npub(super) fn staged_target_matches(record: &CaskTargetRecord, staged: &Path) -> bool {\n    cask_target_fingerprint(staged).is_ok_and(|fingerprint| fingerprint == record.fingerprint)\n}\n","sourceCodeStart":1122,"sourceCodeEnd":1158,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/packages/brew/cask/state.rs#L1122-L1158","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Diff the target at record.path against the staged version copy; if the change is unwanted, restore the original before pruning.","If the change is intentional user data, exclude that target from the prune plan or migrate the data first.","Reinstall the cask to regenerate a consistent receipt and targets, then retry the prune."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"for record in &receipt.targets {\n    if !cask_target_record_matches(record)? {\n        eprintln!(\"target drifted: {}\", record.path.display());\n    }\n}\n// fix or exclude drifted targets before requesting a prune","typeGuard":null,"tryCatchPattern":"match validate_cask_prune_candidate(&receipt, &candidate) {\n    Err(e) if e.to_string().contains(\"artifact target has changed\") => {\n        // inspect/restore drifted targets, then retry\n    }\n    other => other?,\n}","preventionTips":["Avoid editing files inside installed cask targets directly.","Exclude install trees from file-sync/backup tools that rewrite file contents or metadata.","Reinstall the cask if a target was modified, so receipt fingerprints match disk again."],"tags":["brew","cask","receipt","fingerprint-mismatch","validation"],"backgroundTag":"checksum-mismatch","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}