jdx/mise · error
brew-cask: {APP_DIR_ENV} '{}' must be an absolute path
Error message
brew-cask: {APP_DIR_ENV} '{}' must be an absolute path What it means
The brew-cask app-directory override env var (APP_DIR_ENV, e.g. MISE_BREW_CASK_OPT_APPDIR) must be an absolute path because it forms the containment boundary for privileged app symlink placement. `target_app_dir` rejects a relative value with this error. An empty value falls back to the default `/Applications` and is not an error.
Source
Thrown at src/system/packages/brew/cask/paths.rs:168
/// The directory `app` artifacts are linked into: `/Applications` unless
/// [`APP_DIR_ENV`] overrides it.
///
/// The override is validated here rather than at the point of use because
/// `app_target_path` treats the result as a containment boundary for symlinks
/// that may be created with elevated privileges. An empty value falls back to
/// the default so that exporting `MISE_BREW_CASK_OPT_APPDIR=` cannot disable
/// that boundary: `Path::starts_with("")` is true for every path.
pub(super) fn target_app_dir() -> Result<PathBuf> {
let Ok(dir) = crate::env::var(APP_DIR_ENV) else {
return Ok(PathBuf::from(DEFAULT_APP_DIR));
};
if dir.is_empty() {
return Ok(PathBuf::from(DEFAULT_APP_DIR));
}
let dir = PathBuf::from(dir);
if !dir.is_absolute() {
bail!(
"brew-cask: {APP_DIR_ENV} '{}' must be an absolute path",
dir.display()
);
}
if dir
.components()
.any(|component| matches!(component, Component::ParentDir))
{
bail!(
"brew-cask: {APP_DIR_ENV} '{}' must not contain '..'",
dir.display()
);
}
// Resolve the override to a real absolute path: canonicalize its longest
// existing prefix and re-append the components that do not exist yet. This
// makes the appdir a symlink-free containment boundary — privileged cask
// mutations then operate on resolved paths and cannot be redirected through
// a symlinked component — and it collapses every spelling of the filesystemView on GitHub (pinned to afd2eddd3a)
Solutions
- Set the env var to an absolute path, e.g. `export MISE_BREW_CASK_OPT_APPDIR=/Users/me/Apps`
- Unset the var to fall back to the default `/Applications`
- If using a tilde, expand it in the shell or use `$HOME` so the value is absolute
- Fix the script/rc file that sets the variable with a relative value
Example fix
// before (shell) export MISE_BREW_CASK_OPT_APPDIR=Apps // after export MISE_BREW_CASK_OPT_APPDIR="$HOME/Apps"
Defensive patterns
Strategy: validation
Validate before calling
fn appdir_env_ok(v: &str) -> bool {
v.is_empty() || std::path::Path::new(v).is_absolute()
} Try / catch
match result {
Err(e) if e.to_string().contains("must be an absolute path") && e.to_string().contains("APPDIR") => {
eprintln!("set the override to an absolute path, e.g. $HOME/Apps");
}
r => r?,
} Prevention
- Always set the override with an absolute path or $HOME expansion
- Never rely on the current working directory to make a relative value meaningful
- Check shell rc files for unexpanded ~ or relative defaults
- An empty value is allowed and falls back to /Applications
When it happens
Trigger: Exporting the APP_DIR env var to a relative path (e.g. `MISE_BREW_CASK_OPT_APPDIR=Apps`) then running any cask install/validation that resolves the app dir via `target_app_dir`.
Common situations: Set in shell rc with a relative path or `~`-style shorthand unexpanded; typo'd value meant to be under home; carried over from a script run with a different working directory.
Understand the failure class
Background: "is not a valid" / "Invalid ... value" environment variable errors: how libraries validate env vars and what to do when they reject yours — this error's family across 48 libraries.
Related errors
- brew-cask: {APP_DIR_ENV} '{}' must not resolve to the filesy
- brew-cask: refusing generic artifact copy outside Homebrew p
- brew-cask: invalid generic artifact parent
- brew-cask: generic artifact target '{}' must stay below {}
- brew-cask: invalid font target '{}'
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/46519fba91a29027.
Report an issue: GitHub.