{"record":{"id":"7e1423c54419141d","repo":"jdx/mise","slug":"brew-cask-structured-copy-target-already-exi","errorCode":null,"errorMessage":"brew-cask: structured copy target '{}' already exists","messagePattern":"brew-cask: structured copy target '(.+?)' already exists","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask.rs","lineNumber":3579,"sourceCode":"            let sources = flight_symlink_sources(cask, source, *source_glob, staged_path, appdir)?;\n            let [source] = sources.as_slice() else {\n                bail!(\"brew-cask: structured copy source must resolve to exactly one path\");\n            };\n            if !source.exists() {\n                bail!(\n                    \"brew-cask: structured copy source '{}' was not found\",\n                    source.display()\n                );\n            }\n            if source.is_dir() && !recursive {\n                bail!(\"brew-cask: structured directory copy requires recursive=true\");\n            }\n            let target = resolve_flight_path_with_context(cask, target, staged_path, appdir)?;\n            let external = !target.starts_with(staged_path);\n            let target_metadata = target.symlink_metadata().ok();\n            if target_metadata.is_some() {\n                if !overwrite {\n                    bail!(\n                        \"brew-cask: structured copy target '{}' already exists\",\n                        target.display()\n                    );\n                }\n                if external {\n                    targets.protect(&target)?;\n                } else {\n                    file::remove_all(&target)?;\n                }\n            }\n            if let Some(parent) = target.parent() {\n                create_dir_all_elevating(parent)?;\n            }\n            if external && target_metadata.is_none() {\n                // Bind an absent target to its resolved parent only after\n                // creating that parent so rollback can validate its identity.\n                targets.protect(&target)?;\n            }","sourceCodeStart":3561,"sourceCodeEnd":3597,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/src/system/packages/brew/cask.rs#L3561-L3597","documentation":"The copy step's target already exists (`symlink_metadata()` succeeds, which includes dangling symlinks) and the step does not set `overwrite: true`. Rather than clobber the existing file, the step validates the conflict up front and aborts; with `overwrite` it would instead protect (external targets) or remove (staged targets) the existing entry first.","triggerScenarios":"Re-running an install whose previous run already created the target; two artifact steps writing the same target path; a user-created file at the target location.","commonSituations":"Reinstall or upgrade after an incomplete uninstall; converting a move step to a copy step without cleanup; name collision under the appdir with an existing app.","solutions":["Set `overwrite: true` on the copy step when replacing the target is intended","Ensure the previous version's uninstall removed the target (receipts/rollback) before reinstalling","Retarget the copy to a cask-namespaced path that cannot collide with other files"],"exampleFix":"# before\ncopy(source: \"bin/tool\", target: \"#{staged}/bin/tool\")\n# after\ncopy(source: \"bin/tool\", target: \"#{staged}/bin/tool\", overwrite: true)","handlingStrategy":"validation","validationCode":"// Before executing a copy step, detect target conflicts the step would refuse\nlet target = resolve_flight_path_with_context(cask, &step.target, staged_path, appdir)?;\nif target.symlink_metadata().is_ok() && !step.overwrite {\n    return Err(eyre!(\"copy target '{}' exists; set overwrite or remove it first\", target.display()));\n}","typeGuard":null,"tryCatchPattern":"if err.to_string().contains(\"copy target\") && err.to_string().contains(\"already exists\") {\n    // prompt to remove the target or set overwrite, then retry the install\n}","preventionTips":["Run the previous version's uninstall before reinstalling or upgrading","Set `overwrite: true` on copy steps whose targets are cask-owned and disposable","Namespace copy targets under the cask token to avoid collisions"],"tags":["brew-cask","file-copy","overwrite","install-artifact"],"backgroundTag":"target-file-already-exists","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}