zeroclaw-labs/zeroclaw · error
local IPC endpoint lock {} is owned by uid {}, not the daemo
Error message
local IPC endpoint lock {} is owned by uid {}, not the daemon user; remove it or choose a different socket path What it means
The existing lock file `<socket>.lock` is owned by a uid other than the daemon's effective uid. A foreign-owned entry could be locked by another local user to block startup, or unlinked and recreated by its owner to give two daemons different lock inodes, so ZeroClaw refuses to trust it.
Source
Thrown at crates/zeroclaw-runtime/src/rpc/local.rs:334
/// Rejects pre-existing lock entries that do not provide the guarantees a
/// freshly created lock would have.
///
/// The inode must be a regular file owned by the current user with no
/// group/other access, and still linked at the time of inspection. A
/// foreign-owned or permissive entry could be locked by another local
/// user to block startup, or unlinked and recreated by its owner to hand
/// two daemons different lock inodes.
fn require_trusted_lock_file(metadata: &Metadata, lock_path: &Path) -> Result<()> {
if !metadata.file_type().is_file() {
anyhow::bail!(
"local IPC endpoint lock {} is not a regular file; remove it \
or choose a different socket path",
lock_path.display()
);
}
let euid = unsafe { libc::geteuid() };
if metadata.uid() != euid {
anyhow::bail!(
"local IPC endpoint lock {} is owned by uid {}, not the \
daemon user; remove it or choose a different socket path",
lock_path.display(),
metadata.uid()
);
}
if metadata.mode() & 0o077 != 0 {
anyhow::bail!(
"local IPC endpoint lock {} is accessible to other users \
(mode {:o}); restrict it to 0600 or remove it",
lock_path.display(),
metadata.mode() & 0o7777
);
}
if metadata.nlink() == 0 {
anyhow::bail!(
"local IPC endpoint lock {} was unlinked while being opened",
lock_path.display()View on GitHub (pinned to 88bb9c8533)
Solutions
- Remove the stale lock: rm <socket>.lock (as root if needed).
- Or run the daemon as the uid that owns the existing lock file.
- Or choose a different socket path private to the current user.
- Standardize the service user so the lock is always created by the same account.
Example fix
# before: lock created by root, daemon now runs as zeroclaw ls -l /run/zeroclaw/zeroclaw.sock.lock # -rw------- 1 root root ... # after sudo rm /run/zeroclaw/zeroclaw.sock.lock systemctl restart zeroclaw
Defensive patterns
Strategy: validation
Validate before calling
use std::os::unix::fs::MetadataExt;
fn lock_owned_by_me(sock: &std::path::Path) -> bool {
let mut s = sock.as_os_str().to_os_string();
s.push(".lock");
let Ok(md) = std::fs::symlink_metadata(std::path::PathBuf::from(s)) else { return true };
md.uid() == unsafe { libc::geteuid() }
} Try / catch
if !lock_owned_by_me(&sock_path) {
anyhow::bail!("stale foreign-owned lock; rm it as its owner or root");
} Prevention
- Run the daemon under one stable service account so the lock owner never changes.
- Never run one instance as root and another as a user against the same socket path.
When it happens
Trigger: A previous daemon run under a different user account (root, then switched to a service user) left the lock behind; a shared socket path where another user's daemon created the lock first; restoring a state directory from a tarball that changed ownership.
Common situations: Running once with sudo then as the service user (or vice versa); uid changes after user deletion/recreation; shared machines where two users configured the same ZEROCLAW_SOCKET.
Related errors
- local IPC endpoint lock directory {} is owned by uid {}; it
- 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
- local IPC endpoint lock {} was replaced while being acquired
AI-assisted analysis of zeroclaw-labs/zeroclaw@88bb9c8533 (2026-08-23).
Data as JSON: /api/errors/2ea5984463c78b54.
Report an issue: GitHub.