jdx/mise · error
brew-cask: ' ' must not contain '..
Error message
brew-cask: {APP_DIR_ENV} '{}' must not contain '..' What it means
The MISE_BREW_CASK_OPT_APPDIR override must not contain a '..' component. Because the appdir acts as a containment boundary for privileged cask mutations, a parent-directory component could let the appdir resolve outside its intended location; target_app_dir rejects any value with '..' outright rather than normalizing it (src/system/packages/brew/cask/paths.rs:177).
Solutions
- Rewrite the path without '..': resolve it yourself to the real absolute directory, e.g. /opt/apps/../Applications -> /opt/Applications.
- Symlink the desired location to a clean absolute path and set MISE_BREW_CASK_OPT_APPDIR to that path.
- If the '..' came from templating or interpolation, fix the template so it emits a fully resolved absolute path.
- Keep the appdir inside an intended subtree; the validator intentionally forbids escape attempts, so choose a direct absolute path.
Example fix
// before export MISE_BREW_CASK_OPT_APPDIR=/opt/apps/../Applications // after export MISE_BREW_CASK_OPT_APPDIR=/opt/Applications
Defensive patterns
Strategy: validation
Validate before calling
function isValidAppdir(v) {
const p = v ? path.resolve(v) : null;
return !!p && path.isAbsolute(v) && !v.split('/').includes('..') && p !== '/';
} Type guard
function isSafeAppdir(v) {
return typeof v === "string" && v.length > 0 && path.isAbsolute(v) &&
!v.includes('..') && path.resolve(v) !== path.parse(v).root;
} Prevention
- Always export MISE_BREW_CASK_OPT_APPDIR as a clean absolute path with no '..' segments.
- Run realpath on the intended directory (and check it is not '/') before exporting it.
- Prefer creating a dedicated directory (mkdir -p) over reusing paths that need '..' to reach.
- Fix templating so interpolated values emit fully resolved absolute paths.
When it happens
Trigger: Setting MISE_BREW_CASK_OPT_APPDIR to a value containing '..' — e.g. '/opt/apps/../Applications' or '/Applications/../../tmp' — and invoking any cask install/validation path that reaches target_app_dir (via target_path, cask_appdir, app_target_path, or allowed_appdir_roots).
Common situations: Users trying to point the appdir at a sibling directory using '..' shorthand; templated config where variable interpolation leaves a '..' segment; attempts to loosen or redirect the installation boundary that the validation deliberately blocks.
Understand the failure class
Background: Path traversal blocked: "path escapes the workspace" and "outside site root" errors when a path will not stay inside its allowed directory — this error's family across 26 libraries.
Related errors
- brew-cask: ' ' must be an absolute path
- brew-cask: ' ' must not resolve to the filesystem root
- brew-cask: app target
- brew-cask: binary target
- brew-cask: completion target
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/b0de1d2ca0e0ff85.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/packages/brew/cask/paths.rs:177
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 filesystem
// root (`/`, `//`, `/.`, a symlink to `/`, ...) to `/` so they can all be
// rejected together.
let resolved = resolve_appdir(&dir);
if !resolved
.components()
.any(|component| matches!(component, Component::Normal(_)))
{
bail!(
"brew-cask: {APP_DIR_ENV} '{}' must not resolve to the filesystem root",View on GitHub (pinned to 533346cc37)