{"record":{"id":"6a0babd9253e108d","repo":"jdx/mise","slug":"app-target-is-outside-an-allowed-applications-dire","errorCode":null,"errorMessage":"app target is outside an allowed Applications directory: {}","messagePattern":"app target is outside an allowed Applications directory: (.+?)","errorType":"validation","errorClass":"eyre::Report","httpStatus":null,"severity":"warning","filePath":"src/system/packages/brew/cask.rs","lineNumber":7301,"sourceCode":"        bail!(\"receipt target inventory is incomplete or duplicated\");\n    }\n    if records.keys().any(|path| !expected.contains(path)) {\n        bail!(\"receipt target inventory contains an unclassified path\");\n    }\n\n    for path in &receipt.apps {\n        let record = records\n            .get(path)\n            .ok_or_else(|| eyre!(\"missing app target record\"))?;\n        if record.fingerprint.kind != CaskTargetKind::Directory\n            || !allowed_appdir_roots()?\n                .iter()\n                .any(|root| path_is_below(path, root))\n            || !path.file_name().is_some_and(|name| {\n                staged_app_matches_target(record, &candidate.version_dir.join(name))\n            })\n        {\n            bail!(\n                \"app target is outside an allowed Applications directory: {}\",\n                path.display()\n            );\n        }\n    }\n    for path in &receipt.binaries {\n        let record = records\n            .get(path)\n            .ok_or_else(|| eyre!(\"missing binary target record\"))?;\n        if record.fingerprint.kind != CaskTargetKind::Symlink\n            || !allowed_binary_target_roots()\n                .iter()\n                .any(|root| path_is_below(path, root))\n            || !symlink_resolves_below(path, &candidate.version_dir)\n        {\n            bail!(\n                \"binary target is not an owned Caskroom symlink: {}\",\n                path.display()","sourceCodeStart":7283,"sourceCodeEnd":7319,"githubUrl":"https://github.com/jdx/mise/blob/6f52dcdf99e282ef7a7db68c81301fa4618d0f79/src/system/packages/brew/cask.rs#L7283-L7319","documentation":"For each app path in the receipt, the prune validator requires all of: the target record's fingerprint kind is Directory, the path lies below one of the allowed appdir roots (standard Applications directories such as /Applications and ~/Applications via allowed_appdir_roots), and the installed bundle still matches the staged copy inside the Caskroom version directory (staged_app_matches_target). Failing any one refuses the prune — the app is somewhere it must not be or no longer matches what was installed.","triggerScenarios":"The user moved the .app out of an allowed Applications root (e.g. to ~/MyApps or another volume); the app self-updated so its fingerprint differs from the staged Caskroom copy; the record's kind is not Directory; the staged copy in the Caskroom version dir was deleted or modified.","commonSituations":"Self-updating apps (browsers, IDEs, Electron apps) whose bundles change after install; users reorganizing /Applications; custom HOMEBREW_PREFIX setups with non-standard app dirs.","solutions":["If the app self-updated, reinstall the cask (mise install) to refresh fingerprints, then prune — or keep it and accept the skip.","Move the app back under an allowed Applications root at its original path, then retry the prune.","If you intentionally keep apps outside standard roots, uninstall that cask manually instead of pruning it."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Verify each recorded app sits under an allowed Applications root before pruning\nfn app_in_allowed_root(path: &Path, roots: &[PathBuf]) -> bool {\n    roots.iter().any(|root| {\n        path.strip_prefix(root).is_ok_and(|rel| rel.components().next().is_some())\n    })\n}","typeGuard":null,"tryCatchPattern":"Use `if let Err(reason) = validate_cask_prune_candidate(&candidate)` to skip-and-report; never bypass the validator to force deletion of a moved app.","preventionTips":["Leave installed .app bundles at the path the cask installed them.","Reinstall a cask after its app self-updates if you intend to prune it later."],"tags":["homebrew","cask","prune","macos","applications"],"backgroundTag":"path-outside-allowed-root","analyzedSha":"6f52dcdf99e282ef7a7db68c81301fa4618d0f79","analyzedAt":"2026-08-22T10:14:23.840Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}