{"record":{"id":"3b9b440507288c03","repo":"jdx/mise","slug":"brew-cask-completion-target-already-exists-a-3b9b44","errorCode":null,"errorMessage":"brew-cask: completion target '{}' already exists and is not owned by cask '{}'","messagePattern":"brew-cask: completion target '(.+?)' already exists and is not owned by cask '(.+?)'","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/mod.rs","lineNumber":2905,"sourceCode":"    }\n    if let Some(parent) = target.parent() {\n        create_dir_all_elevating(parent)?;\n    }\n    ensure_completion_target_replaceable(cask, artifacts, target)?;\n    make_symlink_elevating(&caskroom_completion, target)?;\n    Ok(())\n}\n\nfn ensure_completion_target_replaceable(\n    cask: &Cask,\n    artifacts: &CaskArtifacts,\n    target: &Path,\n) -> Result<()> {\n    let Ok(metadata) = target.symlink_metadata() else {\n        return Ok(());\n    };\n    if !metadata.file_type().is_symlink() {\n        bail!(\n            \"brew-cask: completion target '{}' already exists and is not owned by cask '{}'\",\n            target.display(),\n            cask.token\n        );\n    }\n    let link_target = std::fs::read_link(target)?;\n    let resolved = resolve_symlink_target(target, link_target);\n    let token_dir = caskroom_token_dir(&cask.token);\n    if path_starts_with_resolved_root(&resolved, &token_dir) {\n        return Ok(());\n    }\n    for completion in &artifacts.completions {\n        if completion.target_path()? != target {\n            continue;\n        }\n        if let Some(source) = appdir_artifact_source(&completion.source, &artifacts.apps)?\n            && file::same_file(&resolved, &source)\n        {","sourceCodeStart":2887,"sourceCodeEnd":2923,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/packages/brew/cask/mod.rs#L2887-L2923","documentation":"When linking a cask completion artifact, mise refuses to overwrite an existing target that is not a symlink. If the destination path already exists as a regular file, directory, or other non-symlink, it cannot have been created by this cask, so bail! protects the pre-existing file from being clobbered, naming the cask token that wanted the target.","triggerScenarios":"Installing a cask whose completion target path already exists on disk as a non-symlink (regular file or directory) — symlink_metadata() succeeds and file_type().is_symlink() is false.","commonSituations":"The user or another package manager previously placed a real file/directory at the target (e.g. /usr/local/bin/tool); a previous install created a directory where the cask wants a symlink; switching tools (e.g. from real brew to mise-managed casks) with leftovers in place.","solutions":["Back up and remove/rename the existing non-symlink file at the target path, then retry the install.","Confirm the existing file is not needed: if it belongs to another package, remove that package instead.","If the path should be a cask-owned symlink, delete the stale file/directory manually and reinstall the cask.","Check whether an old install method (native brew cask) left the artifact and clean it up."],"exampleFix":"// before: real file blocks the cask symlink\nls -l /usr/local/bin/mytool  # -rwxr-xr-x regular file\n\n// after: move it aside and reinstall\nmv /usr/local/bin/mytool /usr/local/bin/mytool.bak && mise install cask://my-tool","handlingStrategy":"validation","validationCode":"use std::path::Path;\nfn link_target_free_or_symlink(target: &Path) -> bool {\n    match target.symlink_metadata() {\n        Ok(md) => md.file_type().is_symlink(),\n        Err(_) => true, // does not exist: safe\n    }\n}","typeGuard":"fn is_symlink_target(target: &std::path::Path) -> bool {\n    target\n        .symlink_metadata()\n        .map(|md| md.file_type().is_symlink())\n        .unwrap_or(false)\n}","tryCatchPattern":"// Rust\nif let Err(e) = install_cask_completion(&cask, &artifacts, &caskroom, &target) {\n    if e.to_string().contains(\"already exists and is not owned\") {\n        // prompt: back up & remove the existing file, then retry\n    } else {\n        return Err(e);\n    }\n}","preventionTips":["Before installing casks, scan completion target dirs for pre-existing regular files.","Avoid letting multiple package managers own the same bin paths.","Use one installation method per binary target.","Back up any file you remove from a completion target directory."],"tags":["brew-cask","symlink","file-already-exists","conflict"],"backgroundTag":"file-already-exists","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"}