jdx/mise · error · eyre::Report
brew-cask: $APPDIR must prefix a binary target
Error message
brew-cask: $APPDIR must prefix a binary target
What it means
The $APPDIR placeholder is only meaningful as a prefix: binary_target_path handles targets starting with "$APPDIR/" and rejects any other occurrence of the literal "$APPDIR" in a binary target. A placeholder buried mid-path ("bin/$APPDIR/tool") has no defined expansion point, so mise refuses it instead of linking to an unintended location.
Source
Thrown at src/system/packages/brew/cask.rs:6148
if target_name.contains('\0') {
bail!("brew-cask: binary target contains NUL");
}
if let Some(relative) = target_name.strip_prefix("$APPDIR/") {
let relative = Path::new(relative);
if relative.components().next().is_none()
|| relative
.components()
.any(|component| !matches!(component, Component::Normal(_)))
{
bail!("brew-cask: binary $APPDIR target '{target_name}' must stay below Applications");
}
if !allowed_appdir_roots()?.iter().any(|root| root == appdir) {
bail!("brew-cask: invalid appdir '{}'", appdir.display());
}
return Ok(appdir.join(relative));
}
if target_name.contains("$APPDIR") {
bail!("brew-cask: $APPDIR must prefix a binary target");
}
let prefix = prefix::prefix();
let prefix_str = prefix.to_string_lossy();
let target_name = target_name.replace("$HOMEBREW_PREFIX", prefix_str.as_ref());
let path = PathBuf::from(&target_name);
let target = if path.is_absolute() {
path
} else if target_name.contains('/') {
prefix.join(path)
} else {
prefix.join("bin").join(path)
};
if target
.components()
.any(|component| matches!(component, Component::ParentDir))
{
bail!(
"brew-cask: binary target '{}' must not contain '..'",View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Move the placeholder to the front: "$APPDIR/tool" — or drop it and use a normal target relative to the brew prefix
- For prefix-anchored binaries use "$HOMEBREW_PREFIX/bin/tool" or plain "tool"
- Report the malformed stanza upstream if it comes from a tap
Example fix
// before (cask binary target) "target": "bin/$APPDIR/tool" // after "target": "$APPDIR/tool"
Defensive patterns
Strategy: type-guard
Type guard
fn uses_appdir_prefix_correctly(name: &str) -> bool {
match name.find("$APPDIR") {
Some(pos) => name[pos..].starts_with("$APPDIR/"),
None => true,
}
} Try / catch
match binary_target_path(name, &appdir) {
Ok(p) => p,
Err(e) if e.to_string().contains("$APPDIR must prefix") => {
warn!("skipping malformed $APPDIR target: {name}");
continue;
}
Err(e) => Err(e),
} Prevention
- Place $APPDIR only at the very start of a binary target, immediately followed by '/'
- Use $HOMEBREW_PREFIX or bare names for prefix-relative binaries
When it happens
Trigger: A cask binary artifact target containing "$APPDIR" anywhere other than the start, e.g. "bin/$APPDIR/tool" or "foo$APPDIR".
Common situations: Hand-written or templated casks misusing the placeholder; tap generators interpolating variables into the middle of target strings.
Related errors
- brew-cask: binary $APPDIR target '{target_name}' must stay b
- brew-cask: binary target '{}' must not contain '..'
- mise upgrade --monorepo is not implemented yet
- brew-cask: refusing generic artifact copy outside Homebrew p
- brew-cask: invalid generic artifact parent
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/23d91830a225fc94.
Report an issue: GitHub.