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

To ditto a bundle into the staging destination safely, mise opens the destination with O_NOFOLLOW/O_DIRECTORY and then fstats it, requiring st_uid to equal the effective uid. Writing through a directory owned by a different user would let that owner influence the copied bundle, so the operation is refused.

Source

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

        )
    })?;
    let destination = nix::fcntl::openat(
        &dir,
        name,
        nix::fcntl::OFlag::O_RDONLY
            | nix::fcntl::OFlag::O_DIRECTORY
            | nix::fcntl::OFlag::O_NOFOLLOW,
        nix::sys::stat::Mode::empty(),
    )
    .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 9dcfcaa0dc)

Solutions

  1. Take ownership of the staging tree: sudo chown -R "$(whoami)" <Caskroom> (or at least the staging parent named in the error)
  2. Or delete the stale staging directory and let the next run recreate it
  3. Pick one identity (always sudo, or never) for cask operations and stay consistent

Example fix

# before -- earlier sudo run left root-owned staging dirs
sudo ls -ld /opt/homebrew/Caskroom/staging

# after
sudo chown -R "$(whoami)" /opt/homebrew/Caskroom
# or start clean
sudo rm -rf /opt/homebrew/Caskroom/staging
Defensive patterns

Strategy: validation

Validate before calling

use std::os::unix::fs::MetadataExt;

fn staging_dir_owned_by_me(dir: &std::path::Path) -> bool {
    std::fs::metadata(dir)
        .map(|m| m.uid() == unsafe { libc::geteuid() } as u32)
        .unwrap_or(false)
}

Try / catch

match stage_bundle(from, dir) {
    Err(e) if e.to_string().contains("not owned by the current user") => {
        eprintln!("remediate with: sudo chown -R \"$(whoami)\" <staging parent>, then retry");
        return Err(e);
    }
    other => other?,
}

Prevention

When it happens

Trigger: The staging directory (or an ancestor left in the Caskroom) is owned by root because a previous run used sudo while the current run is unprivileged, or the reverse; Caskroom ownership changed outside mise.

Common situations: Mixing sudo and non-sudo cask installs; brew permission-repair tools rewriting Caskroom ownership; Caskroom copied or restored with different ownership.

Related errors


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