{"record":{"id":"2e47dddb532f173c","repo":"jdx/mise","slug":"brew-cask-app-target-target-name-must-be-unde-2e47dd","errorCode":null,"errorMessage":"brew-cask: app target '{target_name}' must be under {}","messagePattern":"brew-cask: app target '(.+?)' must be under (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/paths.rs","lineNumber":141,"sourceCode":"        {\n            bail!(\"brew-cask: app target '{target_name}' must not contain '..'\");\n        }\n        if path.is_absolute() {\n            let prefix_app_dir = prefix::prefix().join(\"Applications\");\n            if path.starts_with(&app_dir) || path.starts_with(&prefix_app_dir) {\n                return Ok(path);\n            }\n            // Casks routinely hardcode an absolute `/Applications/Foo.app`\n            // target. When an override appdir is configured, relocate such a\n            // target into it (preserving any subdirectories) rather than\n            // rejecting it. `$HOMEBREW_PREFIX`-anchored targets are handled by\n            // the check above and are never relocated.\n            if app_dir != Path::new(DEFAULT_APP_DIR)\n                && let Ok(rest) = path.strip_prefix(DEFAULT_APP_DIR)\n            {\n                return Ok(app_dir.join(rest));\n            }\n            bail!(\n                \"brew-cask: app target '{target_name}' must be under {}\",\n                app_dir.display()\n            );\n        }\n        bail!(\"brew-cask: app target '{target_name}' must be an absolute path\");\n    }\n    Ok(app_dir.join(target_name))\n}\n\n/// The directory `app` artifacts are linked into: `/Applications` unless\n/// [`APP_DIR_ENV`] overrides it.\n///\n/// The override is validated here rather than at the point of use because\n/// `app_target_path` treats the result as a containment boundary for symlinks\n/// that may be created with elevated privileges. An empty value falls back to\n/// the default so that exporting `MISE_BREW_CASK_OPT_APPDIR=` cannot disable\n/// that boundary: `Path::starts_with(\"\")` is true for every path.\npub(super) fn target_app_dir() -> Result<PathBuf> {","sourceCodeStart":123,"sourceCodeEnd":159,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/packages/brew/cask/paths.rs#L123-L159","documentation":"`app_target_path` accepts absolute app targets only when they fall under the configured app dir (`/Applications` by default, or the APP_DIR override) or the Homebrew prefix's Applications dir. An absolute target outside those roots is rejected so cask installs cannot place privileged symlinks in arbitrary locations. With an override appdir configured, hardcoded `/Applications/...` targets are relocated instead of rejected; anything else fails with this error.","triggerScenarios":"Calling install/validation via `app_target_path` with a cask `app target:` containing an absolute path that starts outside the app dir and the Homebrew prefix Applications dir, e.g. `target: '/System/Foo.app'` while no relocation rule applies.","commonSituations":"Casks hardcoding unusual absolute destinations; a custom MISE_BREW_CASK_OPT_APPDIR pointing somewhere the target doesn't fall under; a cask written for a different layout; typos in the target path.","solutions":["Change the cask target to a bare app-bundle name (`Foo.app`) so it is placed under the app dir automatically","Make the target absolute under the allowed app dir, e.g. `/Applications/Foo.app` or `$HOMEBREW_PREFIX/Applications/Foo.app`","If you use an APP_DIR override, set the target relative (no leading `/`) so it is joined to the override dir","Check the APP_DIR env var value — an unusual override shrinks the set of accepted absolute targets"],"exampleFix":"// before (cask stanza)\napp target: '/System/Library/Foo.app'\n// after\napp target: 'Foo.app'","handlingStrategy":"validation","validationCode":"fn absolute_target_in_allowed_roots(target: &str, app_dir: &std::path::Path) -> bool {\n    let p = std::path::PathBuf::from(target.replace(\"$HOMEBREW_PREFIX\", \"/opt/homebrew\"));\n    p.is_absolute()\n        && (p.starts_with(app_dir) || p.starts_with(\"/opt/homebrew/Applications\")\n            || p.starts_with(\"/Applications\"))\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"must be under\") && e.to_string().contains(\"app target\") => {\n        eprintln!(\"move the target under the app dir or use a bare name\");\n    }\n    r => r?,\n}","preventionTips":["Keep app targets as bare `*.app` names whenever possible","Absolute targets should always begin with /Applications, $HOMEBREW_PREFIX/Applications, or your configured override dir","When using an APP_DIR override, avoid hardcoded absolute /Applications targets unless relocation applies","Validate custom casks against the allowed roots before installing"],"tags":["path-validation","brew-cask","containment"],"backgroundTag":"invalid-argument-value","analyzedSha":"afd2eddd3a50c16190efc1c7e94404b48f72af57","analyzedAt":"2026-09-09T01:38:25.179Z","contentChangedAt":"2026-09-09T01:38:25.179Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}