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
- Give the binary target a concrete destination filename, e.g. '$APPDIR/MyApp.app/Contents/MacOS/tool' or 'bin/tool'.
- If you intended a simple install into the brew bin, use a bare target name like 'tool' rather than a directory path.
- 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
- Author binary targets as concrete filenames ('tool') or full destinations, never bare roots.
- Assert every target has a non-empty remainder after stripping its root.
- Validate templated targets after rendering, when empty variables are visible.
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
- brew-cask: invalid completion target '{}'
- brew-cask: binary artifact '{}' was staged but symlink targe
- brew-cask: binary artifact '{}' was not staged
- brew-cask:{}: invalid {kind} run command path {}
- brew-cask:{}: unsupported {kind} {field} base {}
AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22).
Data as JSON: /api/errors/615be84966f615ee.
Report an issue: GitHub.