{"record":{"id":"d610a058ca9ca8c9","repo":"jdx/mise","slug":"app-target-is-outside-an-allowed-applications-dire-d610a0","errorCode":null,"errorMessage":"app target is outside an allowed Applications directory: {}","messagePattern":"app target is outside an allowed Applications directory: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/state.rs","lineNumber":1076,"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":1058,"sourceCodeEnd":1094,"githubUrl":"https://github.com/jdx/mise/blob/533346cc374382b41ec5ff70536252b2e96e725c/src/system/packages/brew/cask/state.rs#L1058-L1094","documentation":"Before pruning a staged cask, mise verifies each app target recorded in the receipt is a Directory-kind target located under one of the allowed Applications directories (allowed_appdir_roots) and that the staged copy in the version dir matches the target's fingerprint. If the path is outside every allowed Applications root, or the staged app no longer matches, deletion is refused to avoid removing files mise does not provably own.","triggerScenarios":"Calling cask_prune_plan_from_tokens or apply_cask_prune_plan_in when receipt.apps contains a path not under an allowed Applications dir (e.g. a custom 'appdir:' install location), the target's fingerprint kind is not Directory, or the staged app in candidate.version_dir does not match the target record (app renamed, modified, or replaced).","commonSituations":"User moved the .app out of /Applications or installed with a custom appdir so the receipt path no longer matches allowed roots; the app was updated/modified in place so the staged fingerprint no longer matches; a receipt written under a different HOMEBREW_CASKROOM or appdir setting.","solutions":["Verify the app still exists at the receipt path inside an allowed Applications directory; reinstall the cask with mise to regenerate the receipt for the current location","If the app was customized via HOMEBREW_CASK_OPTS appdir, ensure the pruning mise instance sees the same appdir roots","Replace or restore the modified .app so the staged fingerprint matches, then retry the prune","Remove the cask manually or via brew instead of mise direct-artifact pruning"],"exampleFix":"// before: app relocated outside allowed roots, fingerprint mismatch\n/Applications/Custom/Foo.app  // not below allowed_appdir_roots()\n// after: reinstall so receipt matches actual location\nmv /Applications/Custom/Foo.app /Applications/Foo.app\nmise uninstall brew-cask:foo && mise install brew-cask:foo","handlingStrategy":"validation","validationCode":"// pre-flight: confirm each app target is under an allowed Applications root\nfn apps_in_allowed_roots(receipt: &CaskReceipt) -> Result<(), PathBuf> {\n    let roots = allowed_appdir_roots()?;\n    receipt.apps.iter().find(|p| !roots.iter().any(|r| path_is_below(p, r)))\n        .map_or(Ok(()), Err)\n}","typeGuard":"fn app_target_is_safe(path: &Path, roots: &[PathBuf]) -> bool {\n    path.file_name().is_some()\n        && path.metadata().map(|m| m.is_dir()).unwrap_or(false)\n        && roots.iter().any(|root| path_is_below(path, root))\n}","tryCatchPattern":"match apply_cask_prune_plan_in(&plan) {\n    Ok(removed) => info!(\"pruned {removed} casks\"),\n    Err(e) if e.to_string().contains(\"outside an allowed Applications directory\") => {\n        warn!(\"app relocated or modified; reinstalling cask instead: {e:#}\");\n        // fall back to uninstall+install to regenerate the receipt\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Don't move cask-installed .app bundles out of the Applications dir recorded at install time","Use the same HOMEBREW_CASK_OPTS appdir for installing and pruning environments","Avoid modifying .app contents after install (in-place updates invalidate staged fingerprints)","Reinstall the cask rather than hand-editing receipts when install locations change"],"tags":["brew","cask","validation","filesystem","path-safety"],"backgroundTag":"invalid-argument-value","analyzedSha":"533346cc374382b41ec5ff70536252b2e96e725c","analyzedAt":"2026-09-17T13:35:38.149Z","contentChangedAt":"2026-09-17T13:35:38.149Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}