jdx/mise · error
brew-cask: app target
Error message
brew-cask: app target '{target_name}' must be an absolute path What it means
brew-cask `app` artifact targets that contain a path separator (or $HOMEBREW_PREFIX/$APPDIR interpolation) must resolve to an absolute path so the install can verify they land inside the approved app directory or Homebrew prefix. A relative multi-segment target like 'subdir/Foo.app' cannot be safely bounded, so app_target_path rejects it at src/system/packages/brew/cask/paths.rs:146 instead of guessing where to place it.
Solutions
- Remove the '/' from the target or make it absolute: prefix it with '/' (or anchor it with $HOMEBREW_PREFIX or $APPDIR if the artifact belongs in the prefix or an appdir).
- If the target was meant to sit in the configured app dir, drop the directory components and keep only the bundle name (e.g. 'Foo.app'), which app_target_path joins onto the appdir automatically.
- If an absolute location under /Applications was intended but the leading slash was lost, restore it: 'Applications/Foo.app' -> '/Applications/Foo.app' or '$HOMEBREW_PREFIX/Applications/Foo.app'.
- For custom casks, fix the upstream cask source so the app target is either a bare bundle name or a valid absolute/interpolated path.
Example fix
// before (cask stanza) app [["subdir/Foo.app"]] // after app [["Foo.app"]]
Defensive patterns
Strategy: validation
Validate before calling
fn is_valid_app_target(t: &str) -> bool {
if t.contains('\0') { return false; }
if !t.contains('/') { return true; }
let expanded = t.replace("$HOMEBREW_PREFIX", "/opt/homebrew");
Path::new(&expanded).is_absolute()
} Type guard
fn valid_app_target(t: &str) -> Option<&str> {
(!t.contains('\0') && (!t.contains('/') || t.starts_with('/') || t.starts_with("$HOMEBREW_PREFIX") || t.starts_with("$APPDIR")))
.then_some(t)
} Prevention
- Keep app targets as bare bundle names ("Foo.app") unless a specific absolute location is required.
- Never hand-edit a cask target to a nested relative path; use the appdir override to relocate installs instead.
- Lint custom casks: every slash-containing app target must start with '/' or $HOMEBREW_PREFIX/$APPDIR.
- Test cask stanzas with a dry-run/validate mode before a real install.
When it happens
Trigger: A cask's `app` stanza (or user-provided app target override) contains a '/' but the resulting path, after $HOMEBREW_PREFIX substitution, is relative — e.g. 'subdir/Foo.app' or './Foo.app'. Raised by app_target_path, called from installed_skip_reason, app_target_paths, install_one_with_ancestors, install_app, validate_adoptable_apps, and appdir_artifact_source.
Common situations: Hand-written or patched cask definitions where the app target was edited to a nested relative path; typos dropping the leading '/' from an absolute target like 'Applications/Foo.app'; tooling that strips a leading slash; custom cask registries with malformed app stanzas.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- brew-cask: app target
- agent ' ' `queue_directories` entry ' ' must be an absolute…
- an implied source entry key must be relative
- bootstrap compose project
- brew-cask: ' ' must be an absolute path
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/b067796926e01f52.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/packages/brew/cask/paths.rs:146
if path.starts_with(&app_dir) || path.starts_with(&prefix_app_dir) {
return Ok(path);
}
// Casks routinely hardcode an absolute `/Applications/Foo.app`
// target. When an override appdir is configured, relocate such a
// target into it (preserving any subdirectories) rather than
// rejecting it. `$HOMEBREW_PREFIX`-anchored targets are handled by
// the check above and are never relocated.
if app_dir != Path::new(DEFAULT_APP_DIR)
&& let Ok(rest) = path.strip_prefix(DEFAULT_APP_DIR)
{
return Ok(app_dir.join(rest));
}
bail!(
"brew-cask: app target '{target_name}' must be under {}",
app_dir.display()
);
}
bail!("brew-cask: app target '{target_name}' must be an absolute path");
}
Ok(app_dir.join(target_name))
}
/// The directory `app` artifacts are linked into: `/Applications` unless
/// [`APP_DIR_ENV`] overrides it.
///
/// The override is validated here rather than at the point of use because
/// `app_target_path` treats the result as a containment boundary for symlinks
/// that may be created with elevated privileges. An empty value falls back to
/// the default so that exporting `MISE_BREW_CASK_OPT_APPDIR=` cannot disable
/// that boundary: `Path::starts_with("")` is true for every path.
pub(super) fn target_app_dir() -> Result<PathBuf> {
let Ok(dir) = crate::env::var(APP_DIR_ENV) else {
return Ok(PathBuf::from(DEFAULT_APP_DIR));
};
if dir.is_empty() {
return Ok(PathBuf::from(DEFAULT_APP_DIR));View on GitHub (pinned to 533346cc37)