zeroclaw-labs/zeroclaw · error

local IPC endpoint lock {} is accessible to other users (mod

Error message

local IPC endpoint lock {} is accessible to other users (mode {:o}); restrict it to 0600 or remove it

What it means

The existing lock file `<socket>.lock` has group or other access bits set (mode & 0o077 != 0). The lock must be 0600: a permissive lock lets other local users read/tamper with endpoint lifecycle state or interfere with the lock protocol, so acquisition fails closed.

Source

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

    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()
            );
        }
        Ok(())
    }

    impl EndpointLock {
        pub(super) fn acquire(path: &Path) -> Result<Self> {
            let mut lock_name = path.as_os_str().to_os_string();

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Tighten it: chmod 600 <socket>.lock.
  2. Or remove it (rm <socket>.lock) and let the daemon recreate it with 0600.
  3. Fix the umask of the creating process (the daemon requests mode 0o600, but pre-existing files are taken as-is).
  4. Check config management/ACL tooling that keeps re-widening the mode.

Example fix

# before
ls -l /run/zeroclaw/zeroclaw.sock.lock   # -rw-r--r-- 1 zeroclaw zeroclaw ...

# after
chmod 600 /run/zeroclaw/zeroclaw.sock.lock
# or: rm /run/zeroclaw/zeroclaw.sock.lock && systemctl restart zeroclaw
Defensive patterns

Strategy: validation

Validate before calling

use std::os::unix::fs::PermissionsExt;
fn lock_mode_private(sock: &std::path::Path) -> bool {
    let mut s = sock.as_os_str().to_os_string();
    s.push(".lock");
    std::fs::symlink_metadata(std::path::PathBuf::from(s))
        .map(|m| m.permissions().mode() & 0o077 == 0)
        .unwrap_or(true)
}

Try / catch

if !lock_mode_private(&sock_path) {
    anyhow::bail!("lock mode too permissive; chmod 600 <socket>.lock");
}

Prevention

When it happens

Trigger: An earlier process created the lock under a permissive umask or someone chmod'ed it wider; a config-management tool normalized permissions on the runtime dir to 0644; the lock was copied/restored with relaxed modes.

Common situations: 'chmod -R a+r' style fixes on state directories; umask 000 in legacy init scripts; packaging that pre-creates the lock with 0644; security scanners flagging the file and an admin loosening instead of tightening other files nearby.

Related errors


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