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

During linking, mise expects each binary artifact to exist as a regular file at its staged caskroom path. Here the path exists as a symlink (symlink_metadata says so) but is_file() is false — the symlink's target does not exist, i.e. the staged payload contains a dangling symlink where a runnable binary was declared. The message reports both the binary stanza source and the (missing) link target.

Source

Thrown at src/system/packages/brew/cask.rs:4877

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 6f52dcdf99)

Solutions

  1. Adjust the binary stanza's source to point at the real executable file rather than a symlink (check the error's reported target path to see where the link was supposed to go).
  2. If the symlink target should exist on this machine (e.g. a system library), install that dependency so the link resolves.
  3. Uninstall and reinstall the cask to restage a clean payload — interrupted staging can leave broken links.
  4. Report the cask upstream if the app genuinely ships dangling symlinks in its distribution.

Example fix

# before — stanza points at a symlink whose target is absent
"binary": ["MyApp.app/Contents/MacOS/tool-link"]

# after — point at the real binary
"binary": ["MyApp.app/Contents/MacOS/tool"]
Defensive patterns

Strategy: validation

Validate before calling

# after staging, confirm every declared binary resolves to a real file
for b in "$(jq -r '.binaries[].source' meta.json)"; do
  P="<caskroom>/$b"
  [ -f "$P" ] || [ -f "$(readlink -f "$P" 2>/dev/null)" ] || echo "broken: $P -> $(readlink "$P" 2>/dev/null)"
done

Prevention

When it happens

Trigger: A cask binary stanza matches a path inside the staged payload that is a symlink whose destination is absent — e.g. an app bundle shipping symlinks to absolute paths like /usr/lib/... that do not exist in this environment, or payload relocation having rewritten the link to a now-invalid location. Read via std::fs::read_link at src/system/packages/brew/cask.rs:4877.

Common situations: macOS apps bundling symlinks meant to resolve only on a full macOS install; installing casks on Linux where framework paths differ; partially extracted or interrupted downloads that left broken links; payloads where the binary stanza pointed at a symlink instead of the real executable.

Related errors


AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22). Data as JSON: /api/errors/acaa630602329011. Report an issue: GitHub.