{"record":{"id":"1eecc5b4e97b53a5","repo":"jdx/mise","slug":"ownership-receipt-has-changed","errorCode":null,"errorMessage":"ownership receipt has changed","messagePattern":"ownership receipt has changed","errorType":"validation","errorClass":"eyre::Report","httpStatus":null,"severity":"warning","filePath":"src/system/packages/brew/cask.rs","lineNumber":7254,"sourceCode":"            .get(&target.path)\n            .is_some_and(|tokens| tokens.iter().any(|token| token != &candidate.token))\n        {\n            bail!(\n                \"artifact target is now claimed by another cask: {}\",\n                target.path.display()\n            );\n        }\n    }\n    Ok(())\n}\n\nfn validate_cask_prune_candidate(candidate: &CaskPruneCandidate) -> Result<()> {\n    if homebrew_metadata_present(&candidate.token) {\n        bail!(\"Homebrew now owns this cask\");\n    }\n    let receipt = &candidate.receipt;\n    if read_receipt(&candidate.version_dir)?.as_ref() != Some(receipt) {\n        bail!(\"ownership receipt has changed\");\n    }\n    if receipt.schema_version != 3 || !receipt.prune_safe || !receipt.pkg_ids.is_empty() {\n        bail!(\"receipt is not marked safe for direct-artifact pruning\");\n    }\n    if !receipt.metadata_only_apps.is_empty() {\n        bail!(\"metadata-only app ownership cannot be proven safely during pruning\");\n    }\n    let records = receipt\n        .targets\n        .iter()\n        .map(|record| (record.path.clone(), record))\n        .collect::<BTreeMap<_, _>>();\n    let expected = receipt\n        .apps\n        .iter()\n        .chain(&receipt.binaries)\n        .chain(&receipt.fonts)\n        .chain(&receipt.completions)","sourceCodeStart":7236,"sourceCodeEnd":7272,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/src/system/packages/brew/cask.rs#L7236-L7272","documentation":"The prune validator re-reads the `.mise-cask.toml` receipt from the cask's Caskroom version directory and compares it against the receipt captured when the prune candidate was built (read_receipt(...) != candidate.receipt). If they differ, ownership may have changed hands between planning and execution, so pruning is refused rather than deleting artifacts installed by a different invocation.","triggerScenarios":"The `.mise-cask.toml` inside `<Caskroom>/<token>/<version>/` is rewritten between candidate discovery and validation — a concurrent mise install/upgrade of the same cask, another process touching the receipt, or a corrupted receipt that now parses to a different value.","commonSituations":"Two mise processes running at once (install in one terminal, prune in another); CI or shell hooks racing interactive use; hand-edited or half-written receipts after a crash.","solutions":["Re-run the prune after the concurrent install/upgrade finishes; the plan is rebuilt from the fresh receipt.","Avoid running multiple mise operations that touch the same Caskroom simultaneously; do not hand-edit `.mise-cask.toml`.","If the receipt is corrupted, reinstall the cask with mise so a consistent receipt is written, then prune.","Clean up leftover `.mise-tmp-*` directories from an interrupted operation and retry."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Re-read and compare the receipt immediately before acting on a prune candidate\nlet current = read_receipt(&candidate.version_dir)?;\nif current.as_ref() != Some(&candidate.receipt) {\n    // someone reinstalled/rewrote the cask; rebuild the plan instead of pruning\n}","typeGuard":null,"tryCatchPattern":"Catch the Err from validate_cask_prune_candidate and push the candidate to the skipped list with the reason, then optionally re-plan; never delete artifacts when ownership is unverifiable.","preventionTips":["Run one mise operation that mutates the Caskroom at a time.","Never hand-edit .mise-cask.toml receipts.","After an interrupted install/upgrade, re-run it to completion before pruning."],"tags":["homebrew","cask","prune","race-condition","receipt"],"backgroundTag":"install-receipt-mismatch","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}