jdx/mise · error
brew-cask: app target
Error message
brew-cask: app target '{target_name}' must not contain '..' What it means
`app_target_path` rejects app targets whose path contains a `..` component (Component::ParentDir). Parent-directory traversal could escape the intended Applications directories, so any target containing `..` is refused as a path-traversal guard.
Solutions
- Rewrite the app target as a direct absolute path under `$HOMEBREW_PREFIX/Applications` (or `/Applications`), removing all `..` segments.
- Use `$HOMEBREW_PREFIX` expansion instead of relative climbing to reach the desired location.
- If the target intentionally lives outside allowed roots, move the app into the prefix Applications dir and target it there.
Example fix
# before app target: "$HOMEBREW_PREFIX/../../Apps/MyApp.app" # after app target: "$HOMEBREW_PREFIX/Applications/MyApp.app"
Defensive patterns
Strategy: validation
Validate before calling
let p = std::path::PathBuf::from(target_name.replace("$HOMEBREW_PREFIX", prefix));
if p.components().any(|c| matches!(c, std::path::Component::ParentDir)) {
return Err("app target must not contain '..'".into());
} Type guard
fn has_parent_dir(p: &std::path::Path) -> bool {
p.components().any(|c| matches!(c, std::path::Component::ParentDir))
} Prevention
- Write app targets as fully-resolved paths with no '..' segments.
- Use $HOMEBREW_PREFIX expansion to reach prefix locations instead of relative climbing.
- Lint cask definitions for '..' in paths before installing.
When it happens
Trigger: Any app target string that yields a `..` component after `$HOMEBREW_PREFIX` expansion — e.g. `../Apps/Foo.app`, `$HOMEBREW_PREFIX/../../Foo.app` — passed through the app install/adopt/validate call sites.
Common situations: A typo or misused variable in a custom app target; a crafted cask definition attempting traversal; copy-pasted paths with stray `..` segments.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- brew-cask: binary target
- brew-cask: generic artifact source is not contained by the…
- brew-cask: invalid generic artifact parent
- brew-cask: refusing generic artifact copy outside Homebrew…
- brew-cask: refusing installer executable outside trusted…
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/f85a7483778c81ce.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/packages/brew/cask/paths.rs:124
return false;
}
}
true
}
pub(super) fn app_target_path(target_name: &str) -> Result<PathBuf> {
let app_dir = target_app_dir()?;
if target_name.contains('\0') {
bail!("brew-cask: app target contains NUL");
}
if target_name.contains('/') {
let target = target_name.replace("$HOMEBREW_PREFIX", &prefix::prefix().to_string_lossy());
let path = PathBuf::from(target);
if path
.components()
.any(|component| matches!(component, Component::ParentDir))
{
bail!("brew-cask: app target '{target_name}' must not contain '..'");
}
if path.is_absolute() {
let prefix_app_dir = prefix::prefix().join("Applications");
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 {}",View on GitHub (pinned to 533346cc37)