jdx/mise · error

brew-cask: binary artifact '{}' was staged but symlink targe

Error message

brew-cask: binary artifact '{}' was staged but symlink target '{}' does not exist

What it means

After staging, a binary artifact that should exist in the caskroom is a dangling symlink: the staged path has symlink metadata but the link's target does not exist. mise treats the artifact as unusable and reports both the declared source and the broken link target.

Source

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

fn cask_appdir(apps: &[AppArtifact]) -> Result<PathBuf> {
    let prefix_app_dir = prefix::prefix().join("Applications");
    for app in apps {
        if app_target_path(app.target_name())?.starts_with(&prefix_app_dir) {
            return Ok(prefix_app_dir);
        }
    }
    target_app_dir()
}

fn link_binary(caskroom: &Path, appdir: &Path, binary: &BinaryArtifact) -> Result<()> {
    let caskroom_binary = caskroom_binary_path(caskroom, appdir, binary)?;
    if !caskroom_binary.is_file() {
        if caskroom_binary
            .symlink_metadata()
            .is_ok_and(|metadata| metadata.file_type().is_symlink())
        {
            let target = std::fs::read_link(&caskroom_binary)?;
            bail!(
                "brew-cask: binary artifact '{}' was staged but symlink target '{}' does not exist",
                binary.source,
                target.display()
            );
        }
        bail!(
            "brew-cask: binary artifact '{}' was not staged",
            binary.source
        );
    }
    let target = binary.target_path(appdir)?;
    if let Some(parent) = target.parent() {
        create_dir_all_elevating(parent)?;
    }
    make_symlink_elevating(&caskroom_binary, &target)?;
    Ok(())
}

View on GitHub (pinned to afd2eddd3a)

Solutions

  1. Delete the broken symlink in the caskroom and reinstall the cask
  2. Verify the cask payload actually contains the file the symlink points to
  3. Reinstall the cask version cleanly (remove the versioned caskroom dir first)

Example fix

// shell before
ls -l ~/Library/Caches/mise/brew-cask/caskroom/<cask>/.../bin/foo  # -> /missing/target
// after
rm ~/Library/Caches/mise/brew-cask/caskroom/<cask>/<version>/bin/foo && mise install
Defensive patterns

Strategy: validation

Validate before calling

if p.symlink_metadata().map(|m| m.file_type().is_symlink()).unwrap_or(false) {
    let t = std::fs::read_link(&p)?;
    if !t.exists() {
        std::fs::remove_file(&p).ok(); // drop dangling link before reinstall
    }
}

Type guard

fn is_dangling_symlink(p: &Path) -> bool {
    p.symlink_metadata().map(|m| m.file_type().is_symlink()).unwrap_or(false)
        && p.metadata().is_err()
}

Try / catch

match install_result {
    Err(e) if e.to_string().contains("symlink target") => {
        clean_caskroom_version(version);
        install_result = install(version);
    }
    _ => {}
}

Prevention

When it happens

Trigger: linking/validating a staged binary whose caskroom path is a symlink pointing to a file that was never staged or has been deleted, detected via read_link followed by the existence check.

Common situations: A previous failed/partial install left a broken symlink in the caskroom, an antivirus or cleanup tool removed the link target, or the cask artifact layout changed between versions leaving stale links.

Related errors


AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09). Data as JSON: /api/errors/94446a74fe7de568. Report an issue: GitHub.