jdx/mise · error

brew-cask: refusing elevated operation because target…

Error message

brew-cask: refusing elevated operation because target appeared: {}

What it means

ensure_target_absent (src/system/packages/brew/cask.rs:2038) is the final pre-sudo existence check: immediately before a privileged copy the destination must not exist (symlink_metadata must report NotFound). If the target appeared after earlier checks — or was there all along — mise refuses rather than overwrite through sudo; a TOCTOU guard against both races and accidental clobbering of existing files with elevated privileges.

Solutions

  1. Inspect the target path in the error: if it is debris from a failed run, remove it (sudo rm) and retry
  2. If another tool owns the file, stop and let that tool manage it — remove the cask request from mise instead
  3. Serialize cask installs on shared or managed machines so no two writers race the same target
Defensive patterns

Strategy: retry

Validate before calling

match target.symlink_metadata() {
    Ok(_) => return Err(anyhow!("target exists - resolve before elevated copy")),
    Err(e) if e.kind() == std::io::ErrorKind::NotFound => {}
    Err(e) => return Err(e.into()),
}

Try / catch

On catch, inspect the target path: if it is debris from a failed run, remove it and retry the install exactly once; if another tool created it, stop and let that tool own the file.

Prevention

When it happens

Trigger: Another process creating the destination file while mise's install runs between its earlier checks and the privileged copy: a concurrent mise/brew install, a management agent, or an app self-healing helper; also leftover targets from a previous failed run that the flow did not expect.

Common situations: Parallel installs of the same cask on shared machines; re-running a failed install whose target file survived; launchd/cron agents recreating binaries mid-provisioning.

Related errors


AI-assisted analysis of jdx/mise@6f52dcdf99 (2026-08-22). Data as JSON: /api/errors/019fceebf5881236. Report an issue: GitHub.

Appendix: source

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

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.
        // Permit that exact prefix, but require every descendant and every
        // other ancestor used by the elevated operation to be non-writable.
        && (mode & 0o020 == 0 || directory == stable_prefix)
}

#[cfg(unix)]
fn ensure_target_absent(target: &Path) -> Result<()> {
    match target.symlink_metadata() {
        Err(err) if err.kind() == std::io::ErrorKind::NotFound => Ok(()),
        Ok(_) => bail!(
            "brew-cask: refusing elevated operation because target appeared: {}",
            target.display()
        ),
        Err(err) => Err(err.into()),
    }
}

#[cfg(unix)]
fn copy_cask_artifact_at<Fd: std::os::fd::AsFd>(
    from: &Path,
    parent: Fd,
    name: &std::ffi::OsStr,
) -> Result<()> {
    use std::os::unix::fs::PermissionsExt;

    let metadata = from.symlink_metadata()?;
    let mode = nix::sys::stat::Mode::from_bits_truncate(
        metadata.permissions().mode() as nix::libc::mode_t

View on GitHub (pinned to 6f52dcdf99)