jdx/mise · critical

brew-cask: refusing elevated operation through mutable direc

Error message

brew-cask: refusing elevated operation through mutable directory {}

What it means

Before performing elevated (privileged) file operations, mise walks every ancestor of the target path and requires each directory to be trusted: owned by root, not world-writable, and group-writable only when it is exactly the Homebrew prefix (the Intel /usr/local root:admin 0775 convention). If any ancestor is user-owned or more permissive, the elevated operation is refused — writing through a mutable directory with privileges would let anyone on the machine plant or swap the file being installed.

Source

Thrown at src/system/packages/brew/cask.rs:1884

        target
            .file_name()
            .ok_or_else(|| eyre!("brew-cask: generic artifact target has no filename"))?,
    ))
}

#[cfg(unix)]
fn validate_strict_elevated_ancestors(path: &Path) -> Result<()> {
    use std::os::unix::fs::MetadataExt;
    let stable_prefix = file::desymlink_path(&prefix::prefix());
    for directory in path.ancestors() {
        let metadata = directory.symlink_metadata()?;
        if !strict_elevated_directory_is_trusted(
            directory,
            &stable_prefix,
            metadata.uid(),
            metadata.mode(),
        ) {
            bail!(
                "brew-cask: refusing elevated operation through mutable directory {}",
                directory.display()
            );
        }
    }
    Ok(())
}

#[cfg(unix)]
fn strict_elevated_directory_is_trusted(
    directory: &Path,
    stable_prefix: &Path,
    uid: u32,
    mode: u32,
) -> bool {
    uid == 0
        && mode & 0o002 == 0
        // Intel Homebrew conventionally uses root:admin 0775 for /usr/local.

View on GitHub (pinned to 9dcfcaa0dc)

Solutions

  1. Fix ownership/permissions of the offending directory (named in the error): sudo chown root:admin <dir> && sudo chmod 755 <dir>
  2. Group-writability is only tolerated on the Homebrew prefix itself; tighten subdirectories
  3. Avoid casks whose artifact targets live in user-writable paths — report them to the tap
Defensive patterns

Strategy: validation

Validate before calling

use std::os::unix::fs::MetadataExt;
fn elevated_path_trusted(path: &Path, prefix: &Path) -> Result<bool> {
    for dir in path.ancestors() {
        let m = dir.symlink_metadata()?;
        let group_ok = m.mode() & 0o020 == 0 || dir == prefix;
        if !(m.uid() == 0 && m.mode() & 0o002 == 0 && group_ok) {
            return Ok(false);
        }
    }
    Ok(true)
}
// call before requesting any elevated cask install

Try / catch

Catch 'refusing elevated operation through mutable directory' and fix the named directory's ownership/permissions; never catch-and-continue with a different, less-checked path.

Prevention

When it happens

Trigger: A cask artifact whose target lives under a user-writable directory (e.g. /Users/<you>/bin, /tmp/...) while mise escalates to install it, or a target under /usr/local where a non-prefix subdirectory is group-writable.

Common situations: Niche casks with artifact targets inside $HOME; systems where directories under /usr/local were chmod'ed to 0775+ by admin tooling; mixed Homebrew prefix conventions on Intel Macs.

Related errors


AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17). Data as JSON: /api/errors/0646ed89044d1755. Report an issue: GitHub.