{"record":{"id":"46519fba91a29027","repo":"jdx/mise","slug":"brew-cask-app-dir-env-must-be-an-absolute-46519f","errorCode":null,"errorMessage":"brew-cask: {APP_DIR_ENV} '{}' must be an absolute path","messagePattern":"brew-cask: (.+?) '(.+?)' must be an absolute path","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/system/packages/brew/cask/paths.rs","lineNumber":168,"sourceCode":"\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> {\n    let Ok(dir) = crate::env::var(APP_DIR_ENV) else {\n        return Ok(PathBuf::from(DEFAULT_APP_DIR));\n    };\n    if dir.is_empty() {\n        return Ok(PathBuf::from(DEFAULT_APP_DIR));\n    }\n    let dir = PathBuf::from(dir);\n    if !dir.is_absolute() {\n        bail!(\n            \"brew-cask: {APP_DIR_ENV} '{}' must be an absolute path\",\n            dir.display()\n        );\n    }\n    if dir\n        .components()\n        .any(|component| matches!(component, Component::ParentDir))\n    {\n        bail!(\n            \"brew-cask: {APP_DIR_ENV} '{}' must not contain '..'\",\n            dir.display()\n        );\n    }\n    // Resolve the override to a real absolute path: canonicalize its longest\n    // existing prefix and re-append the components that do not exist yet. This\n    // makes the appdir a symlink-free containment boundary — privileged cask\n    // mutations then operate on resolved paths and cannot be redirected through\n    // a symlinked component — and it collapses every spelling of the filesystem","sourceCodeStart":150,"sourceCodeEnd":186,"githubUrl":"https://github.com/jdx/mise/blob/afd2eddd3a50c16190efc1c7e94404b48f72af57/src/system/packages/brew/cask/paths.rs#L150-L186","documentation":"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.","triggerScenarios":"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`.","commonSituations":"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.","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"],"exampleFix":"// before (shell)\nexport MISE_BREW_CASK_OPT_APPDIR=Apps\n// after\nexport MISE_BREW_CASK_OPT_APPDIR=\"$HOME/Apps\"","handlingStrategy":"validation","validationCode":"fn appdir_env_ok(v: &str) -> bool {\n    v.is_empty() || std::path::Path::new(v).is_absolute()\n}","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"must be an absolute path\") && e.to_string().contains(\"APPDIR\") => {\n        eprintln!(\"set the override to an absolute path, e.g. $HOME/Apps\");\n    }\n    r => r?,\n}","preventionTips":["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"],"tags":["env-var","path-validation","brew-cask","configuration"],"backgroundTag":"invalid-env-var-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"}