jdx/mise · error

brew-cask: invalid binary target '{}'

Error message

brew-cask: invalid binary target '{}'

What it means

caskroom_binary_path validates that a binary artifact's target lies under an allowed root (the brew prefix, plus /usr/local when different) and then strips that root to compute the path inside the caskroom. If stripping leaves zero components — the target IS the root itself (e.g. '$APPDIR/', the bare prefix, or '/') — there is no file component to link and mise bails with the binary's target_name.

Source

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

    let roots = if is_appdir_binary_target(&binary.target_name()?) {
        let mut roots = allowed_appdir_roots()?;
        roots.extend(allowed_binary_target_roots());
        roots
    } else {
        allowed_binary_target_roots()
    };
    let relative = roots
        .iter()
        .find_map(|root| target.strip_prefix(root).ok())
        .ok_or_else(|| {
            eyre!(
                "brew-cask: binary target '{}' must be under {}",
                target.display(),
                allowed_binary_target_roots_display(&roots)
            )
        })?;
    if relative.components().next().is_none() {
        bail!(
            "brew-cask: invalid binary target '{}'",
            binary.target_name()?
        );
    }
    Ok(caskroom.join(relative))
}

fn cask_artifacts(cask: &Cask) -> Result<CaskArtifacts> {
    let mut artifacts = CaskArtifacts::default();
    for artifact in &cask.artifacts {
        let artifact_type = artifact_type(artifact);
        if let Some(steps) = parse_flight_steps(cask, artifact, "preflight_steps")? {
            artifacts.preflight_steps.extend(steps);
            continue;
        }
        if let Some(steps) = parse_flight_steps(cask, artifact, "postflight_steps")? {
            artifacts.postflight_steps.extend(steps);
            continue;

View on GitHub (pinned to 6f52dcdf99)

Solutions

  1. Give the binary target a concrete destination filename, e.g. '$APPDIR/MyApp.app/Contents/MacOS/tool' or 'bin/tool'.
  2. If you intended a simple install into the brew bin, use a bare target name like 'tool' rather than a directory path.
  3. Lint cask metadata before install: every binary target must have at least one component below its root.

Example fix

# before
"binary": [["MyApp.app/Contents/MacOS/tool", "$APPDIR/"]]

# after
"binary": [["MyApp.app/Contents/MacOS/tool", "tool"]]
Defensive patterns

Strategy: validation

Validate before calling

# every binary target needs a component below its root
jq -r '.binaries[] | .target // empty' meta.json | while read -r t; do
  case "$t" in "$APPDIR"|"$APPDIR/"|"/"|"$(brew --prefix)") echo "degenerate target: $t";; esac
done

Prevention

When it happens

Trigger: A binary stanza target that resolves exactly to an allowed root: target '$APPDIR/' with nothing after it, '/' , the literal brew prefix, or any path normalizing to one of allowed_binary_target_roots(). The guard is `relative.components().next().is_none()` at src/system/packages/brew/cask.rs:4936; note this is the sibling check to the 'must be under' error that fires when the target is outside the roots.

Common situations: Cask metadata where the binary target field was left as a directory or templated to empty; hand-converted Homebrew stanzas ('target: $APPDIR' pasted whole); schema changes where a list field collapsed to a bare root string.

Related errors


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