jdx/mise · error

brew-cask: completion target

Error message

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

What it means

For an existing symlink at a cask completion target, mise resolves it and checks ownership: the link must point at the staged caskroom artifact (or, for appdir artifacts, a file identical to the matching staged app source). If the resolved link points elsewhere, the target is owned by another installation (or a stale link), so mise bails instead of repointing a link it doesn't own.

Solutions

  1. Remove the foreign/stale symlink at the target path and retry the cask install.
  2. Identify what created the link (brew cask, other tool) and uninstall that owner first.
  3. If the link points at a deleted old version, it is stale — delete it and reinstall.
  4. If two tools legitimately conflict, choose one or adjust the completion target in configuration.

Example fix

// before: symlink owned by another install
readlink /usr/local/bin/mytool  # /opt/homebrew/Caskroom/other/1.0/bin/mytool

// after: remove the foreign link and reinstall
rm /usr/local/bin/mytool && mise install cask://my-tool
Defensive patterns

Strategy: validation

Validate before calling

use std::path::Path;
fn link_owned_by_cask(target: &Path, caskroom_prefix: &str) -> bool {
    target
        .read_link()
        .ok()
        .map(|l| l.to_string_lossy().contains(caskroom_prefix))
        .unwrap_or(false)
}

Type guard

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

Try / catch

// Rust
match install_cask_completion(&cask, &artifacts, &caskroom, &target) {
    Err(e) if e.to_string().contains("already points to") => {
        // inspect readlink(target); remove stale/foreign link, then retry once
    }
    other => other,
}

Prevention

When it happens

Trigger: Installing a cask whose completion target already is a symlink, but read_link/resolution shows it points to a path that is not this cask's staged artifact, and it is not same_file to the matching appdir artifact source for cask.token.

Common situations: A symlink created by native Homebrew or another version manager points at its own Cellar/Caskroom; a stale symlink survives after the old cask version was deleted; two casks or tools claim the same binary name (e.g. two CLI tools installing the same shim path).

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/46d9b5098cb90dff. Report an issue: GitHub.

Appendix: source

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

        );
    }
    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)
        {
            return Ok(());
        }
    }
    bail!(
        "brew-cask: completion target '{}' already points to '{}' and is not owned by cask '{}'",
        target.display(),
        resolved.display(),
        cask.token
    )
}

fn find_completion_source(
    stage: &Path,
    caskroom: &Path,
    cask: &Cask,
    apps: &[AppArtifact],
    source: &str,
) -> Result<Option<PathBuf>> {
    for root in [caskroom, stage] {
        if let Some(source) = generated_caskroom_artifact(root, cask, source)
            && source.is_file()
        {

View on GitHub (pinned to 533346cc37)