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
- Point ZEROCLAW_SOCKET at a directory owned by the daemon user (e.g. ~/.local/state/zeroclaw or XDG_RUNTIME_DIR/zeroclaw).
- chown the existing directory to the daemon user (or root): sudo chown zeroclaw:zeroclaw /path/to/dir.
- Run the daemon as the same uid that owns the directory.
- 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
- Give each daemon user a private runtime dir (XDG_RUNTIME_DIR or a state dir) and point ZEROCLAW_SOCKET there.
- Never change the service user without chown'ing the socket directory.
- Add a pre-start check (ExecStartPre) validating directory ownership.
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
- local IPC endpoint lock directory {} is writable by other us
- local IPC endpoint lock {} is owned by uid {}, not the daemo
- local IPC endpoint lock {} is accessible to other users (mod
- local IPC endpoint lock {} is not a regular file; remove it
- local IPC endpoint lock {} was unlinked while being opened
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/8471c7ec03a6ba5f.
Report an issue: GitHub.