zeroclaw-labs/zeroclaw · error

local IPC endpoint lock directory {} is owned by uid {}; it

Error message

local IPC endpoint lock directory {} is owned by uid {}; it must belong to the daemon user or root

What it means

The parent directory of the socket lifecycle lock (`<ZEROCLAW_SOCKET>.lock`) is owned by a uid that is neither the daemon's effective uid nor root. ZeroClaw fails closed because in such a directory another local user could seed or replace the lock entry, blocking startup or handing two daemons different lock inodes.

Source

Thrown at crates/zeroclaw-runtime/src/rpc/local.rs:297

    /// A directory is trustworthy when it is owned by the current user or
    /// root and is not group/other-writable — unless the sticky bit is set,
    /// which restricts unlink and rename to the entry owner and keeps
    /// `/tmp`-style shared socket directories usable.
    fn require_trusted_lock_dir(lock_path: &Path) -> Result<()> {
        let parent = match lock_path.parent() {
            Some(parent) if !parent.as_os_str().is_empty() => parent,
            _ => Path::new("."),
        };
        let metadata = std::fs::metadata(parent).with_context(|| {
            format!(
                "inspecting local IPC endpoint lock directory {}",
                parent.display()
            )
        })?;
        let euid = unsafe { libc::geteuid() };
        let mode = metadata.mode();
        if metadata.uid() != euid && metadata.uid() != 0 {
            anyhow::bail!(
                "local IPC endpoint lock directory {} is owned by uid {}; \
                 it must belong to the daemon user or root",
                parent.display(),
                metadata.uid()
            );
        }
        if mode & 0o022 != 0 && mode & 0o1000 == 0 {
            anyhow::bail!(
                "local IPC endpoint lock directory {} is writable by other \
                 users without the sticky bit; its entries could be replaced. \
                 Restrict it (chmod go-w or +t) or point ZEROCLAW_SOCKET at a \
                 private directory",
                parent.display()
            );
        }
        Ok(())
    }

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Point ZEROCLAW_SOCKET at a directory owned by the daemon user (e.g. ~/.local/state/zeroclaw or XDG_RUNTIME_DIR/zeroclaw).
  2. chown the existing directory to the daemon user (or root): sudo chown zeroclaw:zeroclaw /path/to/dir.
  3. Run the daemon as the same uid that owns the directory.
  4. Do not share the socket directory between users; give each daemon user its own.

Example fix

# before: dir created by another user
export ZEROCLAW_SOCKET=/run/shared/zeroclaw.sock   # /run/shared owned by uid 1001, daemon runs as 1002

# after: private, user-owned socket dir
sudo chown zeroclaw:zeroclaw /run/shared
# or
mkdir -p "$HOME/.local/state/zeroclaw"
export ZEROCLAW_SOCKET="$HOME/.local/state/zeroclaw/zeroclaw.sock"
Defensive patterns

Strategy: validation

Validate before calling

use std::os::unix::fs::MetadataExt;
fn lock_dir_trusted(sock: &std::path::Path) -> bool {
    let dir = sock.parent().unwrap_or(std::path::Path::new("."));
    let Ok(md) = std::fs::metadata(dir) else { return false };
    let euid = unsafe { libc::geteuid() };
    (md.uid() == euid || md.uid() == 0) && (md.mode() & 0o022 == 0 || md.mode() & 0o1000 != 0)
}

Try / catch

if !lock_dir_trusted(&sock_path) {
    return Err(anyhow::anyhow!("socket dir not trusted; fix ownership before start"));
}
let listener = local::serve(&sock_path).await?;

Prevention

When it happens

Trigger: ZEROCLAW_SOCKET points into a directory created by a different user (e.g. a /var/run subdirectory created by a packaging script while the daemon runs as the zeroclaw user); daemon started under a different uid than the one that created the directory (systemd User= changed, running via sudo vs. not).

Common situations: Switching the daemon between root and non-root service accounts; sharing a socket directory between components run as different users; copying a config with an absolute ZEROCLAW_SOCKET from another machine/install.

Related errors


AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23). Data as JSON: /api/errors/8471c7ec03a6ba5f. Report an issue: GitHub.