vercel/turborepo · error · std::io::Error

daemon socket parent is owned by another user: {socket_dir}

Error message

daemon socket parent is owned by another user: {socket_dir}

What it means

secure_unix_dir (endpoint.rs:504) compares metadata.uid() from symlink_metadata against libc::geteuid(); a mismatch yields this PermissionDenied error. The daemon hardens both the socket dir and its parent, so it refuses when either directory is owned by another uid — otherwise a different user could pre-create or rewrite those directories and hijack the socket.

Source

Thrown at crates/turborepo-daemon/src/endpoint.rs:504

#[cfg(unix)]
fn secure_unix_dir(socket_dir: &AbsoluteSystemPath) -> Result<(), std::io::Error> {
    use std::os::unix::fs::{DirBuilderExt, MetadataExt, PermissionsExt};

    std::fs::DirBuilder::new()
        .recursive(true)
        .mode(PRIVATE_DIR_MODE)
        .create(socket_dir.as_std_path())?;

    let metadata = std::fs::symlink_metadata(socket_dir.as_std_path())?;
    if !metadata.file_type().is_dir() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::PermissionDenied,
            format!("daemon socket parent is not a directory: {socket_dir}"),
        ));
    }
    if metadata.uid() != current_uid() {
        return Err(std::io::Error::new(
            std::io::ErrorKind::PermissionDenied,
            format!("daemon socket parent is owned by another user: {socket_dir}"),
        ));
    }

    let mode = metadata.permissions().mode() & 0o777;
    if mode != PRIVATE_DIR_MODE {
        std::fs::set_permissions(
            socket_dir.as_std_path(),
            std::fs::Permissions::from_mode(PRIVATE_DIR_MODE),
        )?;
    }

    Ok(())
}

#[cfg(unix)]
fn set_private_socket_permissions(sock_path: &AbsoluteSystemPath) -> Result<(), std::io::Error> {

View on GitHub (pinned to f9245100cf)

Solutions

  1. Remove the offending directory shown in the message with sufficient privileges (e.g. `sudo rm -rf <path>`) so your uid recreates it
  2. Never mix uids for the same HOME/cache paths; run turbo and daemon as the same user
  3. In containers, keep the runtime dir on a per-uid path (XDG_RUNTIME_DIR) instead of a shared one

Example fix

# bash: clear root-owned daemon dir, restart as yourself
sudo rm -rf ~/.cache/turborepo
turbo daemon restart
Defensive patterns

Strategy: fallback

Validate before calling

// unix: pre-check ownership of socket dir and its parent
let m = std::fs::symlink_metadata(dir)?;
use std::os::unix::fs::MetadataExt;
if m.uid() != unsafe { libc::geteuid() } {
    anyhow::bail!("{dir} owned by uid {}, refusing to start", m.uid());
}

Try / catch

// on ownership mismatch: remove and let the daemon recreate
Err(e) if e.kind() == std::io::ErrorKind::PermissionDenied
    && e.to_string().contains("owned by another user") => {
    // may need elevated removal if root-owned
    std::process::Command::new("sudo").arg("rm").arg("-rf").arg(dir).status()?;
    daemon_start()?;
}

Prevention

When it happens

Trigger: Daemon start when the socket dir or its parent was created by another uid: previously running turbo under sudo, shared HOME between accounts, containers with mismatched uid maps, or root-created leftovers in /tmp-adjacent paths.

Common situations: `sudo turbo ...` once created root-owned ~/.cache/turborepo Shared CI machines where another user's env pointed at the same paths Volume-mounted home dirs with shifted uids

Related errors


AI-assisted analysis of vercel/turborepo@f9245100cf (2026-08-17). Data as JSON: /api/errors/773f6f9bf76bd3b8. Report an issue: GitHub.