{"record":{"id":"1d6178bf5093787c","repo":"Hmbown/CodeWhale","slug":"runtime-chat-owner-lock-is-not-a-regular-file","errorCode":null,"errorMessage":"Runtime Chat owner lock is not a regular file","messagePattern":"Runtime Chat owner lock is not a regular file","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/tui/src/runtime_chat_relay.rs","lineNumber":1586,"sourceCode":"        #[cfg(unix)]\n        {\n            use std::os::unix::fs::OpenOptionsExt as _;\n            options.mode(0o600).custom_flags(libc::O_NOFOLLOW);\n        }\n        #[cfg(windows)]\n        {\n            use std::os::windows::fs::OpenOptionsExt as _;\n            use windows_sys::Win32::Storage::FileSystem::FILE_FLAG_OPEN_REPARSE_POINT;\n            options.custom_flags(FILE_FLAG_OPEN_REPARSE_POINT);\n        }\n        let file = options.open(path).context(\"open Runtime Chat owner lock\")?;\n        if !file\n            .metadata()\n            .context(\"inspect Runtime Chat owner lock\")?\n            .file_type()\n            .is_file()\n        {\n            bail!(\"Runtime Chat owner lock is not a regular file\");\n        }\n        #[cfg(unix)]\n        {\n            use std::os::unix::fs::PermissionsExt as _;\n            file.set_permissions(fs::Permissions::from_mode(0o600))\n                .context(\"protect Runtime Chat owner lock\")?;\n        }\n        // Same-process drop-then-reopen can observe WouldBlock for a brief\n        // window while the previous fd is still closing (#5735). Retry only\n        // that contention; a lock that stays held is still ownership.\n        let deadline = Instant::now() + Duration::from_millis(25);\n        loop {\n            match Self::try_lock_exclusive(&file) {\n                Ok(()) => break,\n                Err(error) if error.kind() == std::io::ErrorKind::WouldBlock => {\n                    if Instant::now() >= deadline {\n                        return Err(error).context(\"acquire Runtime Chat owner lock\");\n                    }","sourceCodeStart":1568,"sourceCodeEnd":1604,"githubUrl":"https://github.com/Hmbown/CodeWhale/blob/73e0f67d83c59909b571efdfc88c4bc28c309cb1/crates/tui/src/runtime_chat_relay.rs#L1568-L1604","documentation":"After opening the Runtime Chat owner lock, RelayScopeLock::acquire verifies via file metadata that the opened path is actually a regular file; if not (fifo, device, socket, directory), it bails. This prevents reading/writing or chmod-ing special files that happen to sit at the lock path.","triggerScenarios":"Acquiring the owner scope lock when the lock path exists but is not a regular file — e.g. a named pipe, socket, or device node was placed at the path, or the open raced with a replacement between the symlink check and open.","commonSituations":"Tampering or misconfigured state directories; someone pointing the lock path at /dev/null or a fifo; corrupted setups where a directory occupies the expected file path.","solutions":["Remove the non-regular entry at the lock path and let the application recreate a regular lock file","Verify the state directory contents (ls -la) and restore a regular file/empty path","Recreate the state directory from scratch if its contents are untrusted","Investigate the process or tool that placed the special file there"],"exampleFix":"// before\nmkfifo ~/.local/state/codewhale/runtime-chat-owner.lock\n// after\nrm ~/.local/state/codewhale/runtime-chat-owner.lock  # recreated as a regular file on next acquire","handlingStrategy":"validation","validationCode":"fn lock_path_is_regular_file(path: &std::path::Path) -> bool {\n    std::fs::metadata(path).map(|m| m.is_file()).unwrap_or(false)\n}","typeGuard":null,"tryCatchPattern":"match RelayScopeLock::acquire(&lock_path) {\n    Err(e) if e.to_string().contains(\"not a regular file\") => {\n        eprintln!(\"lock path is not a regular file; recreating state directory\");\n        std::fs::remove_file(&lock_path)?;\n        RelayScopeLock::acquire(&lock_path)?\n    }\n    other => other?,\n}","preventionTips":["Never redirect the lock path to devices/fifos (e.g. /dev/null) in wrappers or sandboxes","Audit state directory contents after restores or migrations","Recreate the state directory rather than hand-crafting lock entries"],"tags":["security","filesystem","lock"],"backgroundTag":"file-not-found","analyzedSha":"73e0f67d83c59909b571efdfc88c4bc28c309cb1","analyzedAt":"2026-09-22T01:30:00.501Z","contentChangedAt":"2026-09-22T01:30:00.501Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}