{"record":{"id":"477cac109bd6e8ee","repo":"jdx/mise","slug":"brew-cask-cannot-adopt-existing-artifact-is","errorCode":null,"errorMessage":"brew-cask: cannot adopt '{}': existing artifact is not identical to the cask artifact","messagePattern":"brew-cask: cannot adopt '(.+?)': existing artifact is not identical to the cask artifact","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask.rs","lineNumber":1287,"sourceCode":"    // only by name relative to that descriptor. Nothing below resolves a\n    // pathname for the application directory, so a post-validation replacement\n    // of any appdir component — even by the same uid — cannot redirect the\n    // copy, rename, removal, permission repair, or quarantine steps.\n    let parent = ensure_trusted_appdir(\n        logical_target\n            .parent()\n            .ok_or_else(|| eyre!(\"brew-cask: app target has no parent directory\"))?,\n    )?;\n    let name = logical_target\n        .file_name()\n        .ok_or_else(|| eyre!(\"brew-cask: app target has no filename\"))?\n        .to_owned();\n    if adopt && exists_at(&parent.fd, &name)? {\n        if verify_adopt {\n            let source_fingerprint = cask_target_fingerprint(&source)?;\n            let target_fingerprint = cask_target_fingerprint(&logical_target)?;\n            if source_fingerprint != target_fingerprint {\n                bail!(\n                    \"brew-cask: cannot adopt '{}': existing artifact is not identical to the cask artifact\",\n                    logical_target.display()\n                );\n            }\n        }\n        return Ok(true);\n    }\n\n    ditto(&source, &caskroom_app)?;\n    // Suffix hashes stay derived from the logical path so temporary and backup\n    // names are stable across runs.\n    let name_hash = crate::hash::hash_to_str(&logical_target.display().to_string());\n    let tmp_name = replace_bundle_extension(&name, &format!(\"mise-tmp-{name_hash}\"));\n    let old_name = replace_bundle_extension(&name, &format!(\"mise-old-{name_hash}\"));\n    remove_all_at(&parent.fd, &tmp_name)?;\n    ditto_into(&caskroom_app, &parent.fd, &tmp_name)?;\n    activate_app_at(\n        &parent,","sourceCodeStart":1269,"sourceCodeEnd":1305,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/src/system/packages/brew/cask.rs#L1269-L1305","documentation":"During artifact installation with adoption enabled (src/system/packages/brew/cask.rs:1287), mise can adopt an app already present at the destination instead of overwriting it. With verify_adopt set it fingerprints both the staged artifact and the existing target (cask_target_fingerprint); a mismatch means the bytes on disk are not the exact artifact this cask would install, so adoption is refused rather than silently replacing something else.","triggerScenarios":"The brew_cask_adopt manager option is on for a token, the target app already exists at its destination path, and verify_adopt is requested — the fingerprint comparison (content identity of app bundles) fails because the installed app differs from the cask artifact.","commonSituations":"Apps downloaded from the vendor site before switching to mise; apps whose in-app updater rewrote the bundle so it no longer matches the cask's bytes; adoption enabled broadly in config across machines with drifted installs.","solutions":["Quit and remove (or move aside) the existing app at the path shown in the error, then retry the mise install","Disable adoption for that cask token so mise performs its normal install flow instead of the adopt path","If the existing app is simply an older build of the same app, removing it and installing via the cask is the clean path"],"exampleFix":"# before\n$ mise install brew-cask:foo   # adopt fails: existing /Applications/Foo.app differs\n\n# after\n$ mv /Applications/Foo.app ~/Desktop/Foo.app.bak\n$ mise install brew-cask:foo","handlingStrategy":"validation","validationCode":"if adopt && target_exists {\n    let staged = cask_target_fingerprint(&staged_app)?;\n    let existing = cask_target_fingerprint(&target_path)?;\n    if staged != existing {\n        return Err(anyhow!(\"existing app differs from cask artifact - move it aside or disable adopt\"));\n    }\n}","typeGuard":"fn adoptable(staged_fp: &str, existing_fp: &str) -> bool { staged_fp == existing_fp }","tryCatchPattern":null,"preventionTips":["Enable adoption only for casks whose apps you installed from the same artifact source","Expect self-updating apps (browsers, editors) to drift from cask bytes — exclude them from adopt","Fingerprint-compare once before turning adopt on for a token"],"tags":["brew-cask","adopt","fingerprint","conflict"],"backgroundTag":"existing-artifact-conflict","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}