jdx/mise · error

brew-cask: completion target

Error message

brew-cask: completion target '{}' already exists and is not owned by cask '{}'

What it means

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.

Solutions

  1. Back up and remove/rename the existing non-symlink file at the target path, then retry the install.
  2. Confirm the existing file is not needed: if it belongs to another package, remove that package instead.
  3. If the path should be a cask-owned symlink, delete the stale file/directory manually and reinstall the cask.
  4. Check whether an old install method (native brew cask) left the artifact and clean it up.

Example fix

// before: real file blocks the cask symlink
ls -l /usr/local/bin/mytool  # -rwxr-xr-x regular file

// after: move it aside and reinstall
mv /usr/local/bin/mytool /usr/local/bin/mytool.bak && mise install cask://my-tool
Defensive patterns

Strategy: validation

Validate before calling

use std::path::Path;
fn link_target_free_or_symlink(target: &Path) -> bool {
    match target.symlink_metadata() {
        Ok(md) => md.file_type().is_symlink(),
        Err(_) => true, // does not exist: safe
    }
}

Type guard

fn is_symlink_target(target: &std::path::Path) -> bool {
    target
        .symlink_metadata()
        .map(|md| md.file_type().is_symlink())
        .unwrap_or(false)
}

Try / catch

// Rust
if let Err(e) = install_cask_completion(&cask, &artifacts, &caskroom, &target) {
    if e.to_string().contains("already exists and is not owned") {
        // prompt: back up & remove the existing file, then retry
    } else {
        return Err(e);
    }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: "already exists" / EEXIST / FileAlreadyExistsException: what the 'file already exists' error means and how to fix it — this error's family across 37 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/3b9b440507288c03. Report an issue: GitHub.

Appendix: source

Thrown at src/system/packages/brew/cask/mod.rs:2905

    }
    if let Some(parent) = target.parent() {
        create_dir_all_elevating(parent)?;
    }
    ensure_completion_target_replaceable(cask, artifacts, target)?;
    make_symlink_elevating(&caskroom_completion, target)?;
    Ok(())
}

fn ensure_completion_target_replaceable(
    cask: &Cask,
    artifacts: &CaskArtifacts,
    target: &Path,
) -> Result<()> {
    let Ok(metadata) = target.symlink_metadata() else {
        return Ok(());
    };
    if !metadata.file_type().is_symlink() {
        bail!(
            "brew-cask: completion target '{}' already exists and is not owned by cask '{}'",
            target.display(),
            cask.token
        );
    }
    let link_target = std::fs::read_link(target)?;
    let resolved = resolve_symlink_target(target, link_target);
    let token_dir = caskroom_token_dir(&cask.token);
    if path_starts_with_resolved_root(&resolved, &token_dir) {
        return Ok(());
    }
    for completion in &artifacts.completions {
        if completion.target_path()? != target {
            continue;
        }
        if let Some(source) = appdir_artifact_source(&completion.source, &artifacts.apps)?
            && file::same_file(&resolved, &source)
        {

View on GitHub (pinned to 533346cc37)