{"record":{"id":"2ea5984463c78b54","repo":"zeroclaw-labs/zeroclaw","slug":"local-ipc-endpoint-lock-is-owned-by-uid-not","errorCode":null,"errorMessage":"local IPC endpoint lock {} is owned by uid {}, not the daemon user; remove it or choose a different socket path","messagePattern":"local IPC endpoint lock (.+?) is owned by uid (.+?), not the daemon user; remove it or choose a different socket path","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/zeroclaw-runtime/src/rpc/local.rs","lineNumber":334,"sourceCode":"    /// Rejects pre-existing lock entries that do not provide the guarantees a\n    /// freshly created lock would have.\n    ///\n    /// The inode must be a regular file owned by the current user with no\n    /// group/other access, and still linked at the time of inspection. A\n    /// foreign-owned or permissive entry could be locked by another local\n    /// user to block startup, or unlinked and recreated by its owner to hand\n    /// two daemons different lock inodes.\n    fn require_trusted_lock_file(metadata: &Metadata, lock_path: &Path) -> Result<()> {\n        if !metadata.file_type().is_file() {\n            anyhow::bail!(\n                \"local IPC endpoint lock {} is not a regular file; remove it \\\n                 or choose a different socket path\",\n                lock_path.display()\n            );\n        }\n        let euid = unsafe { libc::geteuid() };\n        if metadata.uid() != euid {\n            anyhow::bail!(\n                \"local IPC endpoint lock {} is owned by uid {}, not the \\\n                 daemon user; remove it or choose a different socket path\",\n                lock_path.display(),\n                metadata.uid()\n            );\n        }\n        if metadata.mode() & 0o077 != 0 {\n            anyhow::bail!(\n                \"local IPC endpoint lock {} is accessible to other users \\\n                 (mode {:o}); restrict it to 0600 or remove it\",\n                lock_path.display(),\n                metadata.mode() & 0o7777\n            );\n        }\n        if metadata.nlink() == 0 {\n            anyhow::bail!(\n                \"local IPC endpoint lock {} was unlinked while being opened\",\n                lock_path.display()","sourceCodeStart":316,"sourceCodeEnd":352,"githubUrl":"https://github.com/zeroclaw-labs/zeroclaw/blob/88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc/crates/zeroclaw-runtime/src/rpc/local.rs#L316-L352","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"# before: lock created by root, daemon now runs as zeroclaw\nls -l /run/zeroclaw/zeroclaw.sock.lock   # -rw------- 1 root root ...\n\n# after\nsudo rm /run/zeroclaw/zeroclaw.sock.lock\nsystemctl restart zeroclaw","handlingStrategy":"validation","validationCode":"use std::os::unix::fs::MetadataExt;\nfn lock_owned_by_me(sock: &std::path::Path) -> bool {\n    let mut s = sock.as_os_str().to_os_string();\n    s.push(\".lock\");\n    let Ok(md) = std::fs::symlink_metadata(std::path::PathBuf::from(s)) else { return true };\n    md.uid() == unsafe { libc::geteuid() }\n}","typeGuard":null,"tryCatchPattern":"if !lock_owned_by_me(&sock_path) {\n    anyhow::bail!(\"stale foreign-owned lock; rm it as its owner or root\");\n}","preventionTips":["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."],"tags":["unix","permissions","ownership","ipc","lock-file","startup"],"backgroundTag":"unsafe-file-ownership","analyzedSha":"88bb9c8533fc57ed7a03e36ca7c9ed2bf8336dcc","analyzedAt":"2026-08-23T01:07:41.857Z","schemaVersion":2},"datasetVersion":"2026-08-23T08:06:27.607Z"}