zeroclaw-labs/zeroclaw · error

local IPC endpoint lock {} is not a regular file; remove it

Error message

local IPC endpoint lock {} is not a regular file; remove it or choose a different socket path

What it means

The pre-existing entry at `<socket>.lock` is not a regular file (it is a directory, FIFO, device, etc.). The lock protocol requires a regular file because the advisory flock and the dev/inode identity check only make sense on one; a non-regular entry could also be a DoS vector.

Source

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

                 Restrict it (chmod go-w or +t) or point ZEROCLAW_SOCKET at a \
                 private directory",
                parent.display()
            );
        }
        Ok(())
    }

    /// 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",

View on GitHub (pinned to 88bb9c8533)

Solutions

  1. Inspect the entry: ls -la <socket>.lock and file <socket>.lock.
  2. Remove the offending entry (rm -rf for a dir, rm for a fifo).
  3. Or point ZEROCLAW_SOCKET at a different path so a fresh lock file is created.
  4. Check for the script/tool that created the non-file so it does not reappear.

Example fix

# before: zeroclaw.sock.lock is a directory
ls -ld /run/zeroclaw/zeroclaw.sock.lock   # drwxr-xr-x ...

# after
rm -rf /run/zeroclaw/zeroclaw.sock.lock
systemctl restart zeroclaw
Defensive patterns

Strategy: validation

Validate before calling

fn lock_entry_is_regular(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.file_type().is_file())
        .unwrap_or(true) // absent is fine: daemon will create it
}

Try / catch

if !lock_entry_is_regular(&sock_path) {
    anyhow::bail!("<socket>.lock exists but is not a regular file; remove it");
}

Prevention

When it happens

Trigger: Someone created a directory or named pipe at the exact lock path (mkdir $(dirname sock)/zeroclaw.sock.lock, mkfifo ...); a broken cleanup script or artifact moved a non-file onto the path; symlinks are already rejected earlier at open via O_NOFOLLOW, so this catches other file types.

Common situations: Accidental 'mkdir' instead of 'touch' when pre-creating runtime dirs; leftover objects from experimentation; hostile or buggy co-tenant in a shared directory.

Related errors


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