jdx/mise · error
app target is outside an allowed Applications directory
Error message
app target is outside an allowed Applications directory: {} What it means
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.
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
Example fix
// before: app relocated outside allowed roots, fingerprint mismatch /Applications/Custom/Foo.app // not below allowed_appdir_roots() // after: reinstall so receipt matches actual location mv /Applications/Custom/Foo.app /Applications/Foo.app mise uninstall brew-cask:foo && mise install brew-cask:foo
Defensive patterns
Strategy: validation
Validate before calling
// pre-flight: confirm each app target is under an allowed Applications root
fn apps_in_allowed_roots(receipt: &CaskReceipt) -> Result<(), PathBuf> {
let roots = allowed_appdir_roots()?;
receipt.apps.iter().find(|p| !roots.iter().any(|r| path_is_below(p, r)))
.map_or(Ok(()), Err)
} Type guard
fn app_target_is_safe(path: &Path, roots: &[PathBuf]) -> bool {
path.file_name().is_some()
&& path.metadata().map(|m| m.is_dir()).unwrap_or(false)
&& roots.iter().any(|root| path_is_below(path, root))
} Try / catch
match apply_cask_prune_plan_in(&plan) {
Ok(removed) => info!("pruned {removed} casks"),
Err(e) if e.to_string().contains("outside an allowed Applications directory") => {
warn!("app relocated or modified; reinstalling cask instead: {e:#}");
// fall back to uninstall+install to regenerate the receipt
}
Err(e) => return Err(e),
} Prevention
- 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
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- binary target is not an owned Caskroom symlink
- font target is outside the platform font directory
- app Info.plist must be a regular file
- artifact target has changed
- brew-cask: ' ' must stay below Applications
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/d610a058ca9ca8c9.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/packages/brew/cask/state.rs:1076
bail!("receipt target inventory is incomplete or duplicated");
}
if records.keys().any(|path| !expected.contains(path)) {
bail!("receipt target inventory contains an unclassified path");
}
for path in &receipt.apps {
let record = records
.get(path)
.ok_or_else(|| eyre!("missing app target record"))?;
if record.fingerprint.kind != CaskTargetKind::Directory
|| !allowed_appdir_roots()?
.iter()
.any(|root| path_is_below(path, root))
|| !path.file_name().is_some_and(|name| {
staged_app_matches_target(record, &candidate.version_dir.join(name))
})
{
bail!(
"app target is outside an allowed Applications directory: {}",
path.display()
);
}
}
for path in &receipt.binaries {
let record = records
.get(path)
.ok_or_else(|| eyre!("missing binary target record"))?;
if record.fingerprint.kind != CaskTargetKind::Symlink
|| !allowed_binary_target_roots()
.iter()
.any(|root| path_is_below(path, root))
|| !symlink_resolves_below(path, &candidate.version_dir)
{
bail!(
"binary target is not an owned Caskroom symlink: {}",
path.display()View on GitHub (pinned to 533346cc37)