jdx/mise · error · eyre::Report
brew-cask: binary $APPDIR target '{target_name}' must stay b
Error message
brew-cask: binary $APPDIR target '{target_name}' must stay below Applications What it means
binary_target_path supports the $APPDIR/ placeholder for binaries that must live inside the Applications tree. After stripping "$APPDIR/", the remainder must be non-empty and consist only of Component::Normal entries — no '..', no '.', no embedded absolute segments. This bail rejects placeholders that would escape the Applications subtree.
Source
Thrown at src/system/packages/brew/cask.rs:6140
roots
.iter()
.map(|root| root.display().to_string())
.collect::<Vec<_>>()
.join(" or ")
}
fn binary_target_path(target_name: &str, appdir: &Path) -> Result<PathBuf> {
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 {View on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Use a clean single relative remainder: "$APPDIR/Foo.app/Contents/MacOS/tool"
- Avoid '..' and '.' segments after $APPDIR/
- If the target comes from a tap, report/fix the artifact stanza upstream
Example fix
// before (cask binary target) "target": "$APPDIR/../Foo.app/Contents/MacOS/tool" // after "target": "$APPDIR/Foo.app/Contents/MacOS/tool"
Defensive patterns
Strategy: type-guard
Type guard
use std::path::{Component, Path};
fn is_valid_appdir_binary_target(name: &str) -> bool {
match name.strip_prefix("$APPDIR/") {
Some(rest) => {
let rel = Path::new(rest);
rel.components().next().is_some()
&& rel.components().all(|c| matches!(c, Component::Normal(_)))
}
None => true, // non-$APPDIR targets follow other rules
}
} Try / catch
match binary_target_path(name, &appdir) {
Ok(p) => p,
Err(e) if e.to_string().contains("must stay below Applications") => {
warn!("skipping unsafe $APPDIR binary target: {name}");
continue;
}
Err(e) => Err(e),
} Prevention
- Keep $APPDIR targets a single clean relative remainder with no '..', '.', or empty segments
- Use $APPDIR only as a leading prefix followed by exactly one '/'
When it happens
Trigger: A binary target of exactly "$APPDIR/" (empty remainder), or "$APPDIR/../Foo.app", or any $APPDIR-relative target whose component list contains a non-Normal component.
Common situations: Hand-written casks using $APPDIR incorrectly; malicious or malformed taps; copy-paste errors like "$APPDIR//tool" or "$APPDIR/./tool".
Related errors
- brew-cask: $APPDIR must prefix a binary target
- brew-cask: binary target '{}' must not contain '..'
- brew-cask:{}: invalid {kind} {field} path {}
- brew-cask: app target '{target_name}' must not contain '..'
- brew-cask: {APP_DIR_ENV} '{}' must not contain '..'
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/706d53bd75e6f42e.
Report an issue: GitHub.