jdx/mise · error
brew-cask: refusing elevated operation because target appear
Error message
brew-cask: refusing elevated operation because target appeared: {} What it means
Elevated installs are only allowed to create targets, never overwrite: right before the privileged rename/copy, mise stats the target (ensure_target_absent). If anything — file, symlink, or directory — now exists where the plan assumed absence, the operation is refused. This closes the TOCTOU window where a swapped-in symlink at the target could redirect a privileged write.
Source
Thrown at src/system/packages/brew/cask.rs:1912
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_tView on GitHub (pinned to 9dcfcaa0dc)
Solutions
- Identify what created the target (path is in the error); if it came from a concurrent install, let it finish and re-run mise — it will detect the existing version
- If the target is stale, remove it deliberately (verify it is not a symlink someone else planted) and retry
- Serialize installers so two privileged writers never race the same path
Defensive patterns
Strategy: try-catch
Validate before calling
// Best-effort pre-check (still racy — the library re-checks atomically):
fn target_absent(target: &Path) -> bool {
matches!(target.symlink_metadata(), Err(e) if e.kind() == std::io::ErrorKind::NotFound)
} Try / catch
Catch 'refusing elevated operation because target appeared'; verify the appeared target's provenance (lstat it, check owner and symlink-ness), remove it if it is your own stale artifact, then retry. Never blindly unlink — the whole point of the guard is that something raced you.
Prevention
- Serialize privileged installers so two writers never target the same path
- Don't run mise bootstrap while login scripts recreate symlinks in target directories
When it happens
Trigger: Something creates the target path between mise's earlier planning and the elevated step: a concurrent installer (brew, another mise run, a package installer), a login script, or an attacker racing the install.
Common situations: Parallel bootstrap scripts installing the same binary; re-running mise while a previous run's elevated step is still finishing; dotfiles daemons that continuously recreate symlinks.
Related errors
- brew-cask:{}: Homebrew took ownership of this cask while ins
- brew-cask: invalid {kind} '{value}'
- brew-cask: staged symlink path escaped extraction root: {}
- brew-cask: refusing generic artifact source outside the extr
- brew-cask: refusing to stage generic artifact through a path
AI-assisted analysis of jdx/mise@9dcfcaa0dc (2026-08-17).
Data as JSON: /api/errors/019fceebf5881236.
Report an issue: GitHub.