jdx/mise · error
brew-cask: staging directory is not owned by the current use
Error message
brew-cask: staging directory is not owned by the current user
What it means
Before copying bundle contents into the destination staging directory with ditto, the library opens the directory and fstat()s it, verifying it is owned by the current effective uid. If the staging directory is owned by someone else (e.g. created by root or another user), proceeding could let an untrusted directory's contents be manipulated, so the operation is refused.
Source
Thrown at src/system/packages/brew/cask/mod.rs:2431
/// A racing creation of `name` surfaces as `EEXIST` and fails closed rather than
/// being followed.
#[cfg(unix)]
fn ditto_into<Fd: std::os::fd::AsFd>(from: &Path, dir: Fd, name: &std::ffi::OsStr) -> Result<()> {
nix::sys::stat::mkdirat(&dir, name, nix::sys::stat::Mode::S_IRWXU).wrap_err_with(|| {
format!(
"brew-cask: cannot create staging directory {}",
Path::new(name).display()
)
})?;
let destination = open_dir_nofollow_at(&dir, name).wrap_err_with(|| {
format!(
"brew-cask: cannot open staging directory {}",
Path::new(name).display()
)
})?;
let stat = nix::sys::stat::fstat(&destination)?;
if stat.st_uid != nix::unistd::geteuid().as_raw() {
bail!("brew-cask: staging directory is not owned by the current user");
}
// `ditto src dst` copies the *contents* of src into dst, so pointing it at
// the bound directory reproduces the bundle in place.
let status = run_in_trusted_dir(
"ditto",
&[from.as_os_str(), std::ffi::OsStr::new(".")],
&destination,
)?;
if !status.success() {
bail!(
"ditto failed copying {} to {}",
from.display(),
Path::new(name).display()
);
}
// Restore the bundle's own permissions, which the private staging mode hid.
if let Ok(metadata) = from.symlink_metadata() {
use std::os::unix::fs::PermissionsExt;View on GitHub (pinned to afd2eddd3a)
Solutions
- Delete the root-owned staging directory (sudo rm -rf) and rerun the install as the normal user
- Stop running mise installs with sudo; chown -R "$USER" the mise cache/temp directories if needed
- In CI, ensure all steps run under the same user account
Example fix
// before sudo mise install <cask> # leaves root-owned staging dirs // after sudo rm -rf "$(mise cache dir)"/.../staging-* chown -R "$USER" "$(mise cache dir)" mise install <cask>
Defensive patterns
Strategy: validation
Validate before calling
use nix::sys::stat::fstat;
let stat = fstat(&dir)?;
if stat.st_uid != nix::unistd::geteuid().as_raw() {
panic!("staging dir owned by uid {}; remove it and rerun as current user", stat.st_uid);
} Type guard
fn staging_owned_by_me(dir: &impl nix::NixPath) -> bool {
nix::sys::stat::fstat(dir)
.map(|s| s.st_uid == nix::unistd::geteuid().as_raw())
.unwrap_or(false)
} Try / catch
match result {
Err(e) if e.to_string().contains("not owned by the current user") => {
eprintln!("delete the root-owned staging dir and reinstall without sudo");
}
Err(e) => return Err(e),
Ok(v) => v,
} Prevention
- Never run mise installs under sudo
- chown -R "$USER" the mise cache/temp dirs after user changes
- In CI, keep all install steps under one user account
When it happens
Trigger: Opening the pre-created staging directory (by name under the mise temp/cask dir) succeeds but fstat shows st_uid != geteuid() — the directory exists but belongs to root or another account.
Common situations: A previous install was run with sudo/root, leaving root-owned staging dirs; running mise under a different user than the one that seeded the cache; CI switching between users.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- brew-cask: temporary artifact directory is not private
- brew-cask: refusing elevated operation through mutable direc
- brew-cask: refusing operation through untrusted directory {}
- brew-cask: refusing elevated operation through mutable direc
- brew-cask:{}: Homebrew owns this cask; remove it with Homebr
AI-assisted analysis of jdx/mise@afd2eddd3a (2026-09-09).
Data as JSON: /api/errors/1a42fe7ac2a5e489.
Report an issue: GitHub.