{"record":{"id":"68ec966283d66fb6","repo":"xai-org/grok-build","slug":"process-group-id-pid-exceeds-i32-max-cannot-be","errorCode":null,"errorMessage":"process-group id {pid} exceeds i32::MAX; cannot be used with killpg","messagePattern":"process-group id (.+?) exceeds i32::MAX; cannot be used with killpg","errorType":"exception","errorClass":"io::Error","httpStatus":null,"severity":"error","filePath":"crates/codegen/xai-tty-utils/src/lib.rs","lineNumber":626,"sourceCode":"    /// Validate a group-leader pid. Errors for pid `0` (the caller's own\n    /// group), pid `1` (init), or the caller's own process group (signalling it\n    /// would kill this very process). A child spawned into its own group\n    /// (`setpgid`/`setsid`, e.g. via [`new_process_group`] or a `detach_*`\n    /// helper) always has a leader pid `> 1` distinct from the caller's pgid, so\n    /// a well-formed enrollment never trips this — it only catches a child that\n    /// was never grouped, which would otherwise broadcast the kill.\n    pub fn new(pid: u32) -> io::Result<Self> {\n        if pid <= 1 {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                format!(\"refusing degenerate process-group id {pid} (0 = own group, 1 = init)\"),\n            ));\n        }\n        // killpg_unix casts `pid as i32`; values > i32::MAX wrap to negative,\n        // and killpg with a negative pgid returns EINVAL on Linux/macOS. Reject\n        // here so the invariant is safe-by-construction, not safe-by-OS-quirk.\n        if pid > i32::MAX as u32 {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                format!(\"process-group id {pid} exceeds i32::MAX; cannot be used with killpg\"),\n            ));\n        }\n        if i64::from(pid) == i64::from(nix::unistd::getpgrp().as_raw()) {\n            return Err(io::Error::new(\n                io::ErrorKind::InvalidInput,\n                format!(\"refusing to killpg the caller's own process group ({pid})\"),\n            ));\n        }\n        Ok(Self(pid))\n    }\n\n    /// The validated raw process-group id.\n    pub fn get(self) -> u32 {\n        self.0\n    }\n}","sourceCodeStart":608,"sourceCodeEnd":644,"githubUrl":"https://github.com/xai-org/grok-build/blob/bc7f02eddd3d84085849dc19ed216f11c23b0571/crates/codegen/xai-tty-utils/src/lib.rs#L608-L644","documentation":"killpg takes a pid_t (i32); u32 pids above i32::MAX wrap to negative when cast, and killpg with a negative pgid fails with EINVAL (or signals a different group). ProcessGroup::new rejects such ids up front as InvalidInput so the invariant doesn't rely on OS quirks.","triggerScenarios":"Calling ProcessGroup::new with a pid greater than 2147483647 — possible on systems configured with very high pid_max, or from corrupt/stale bookkeeping data.","commonSituations":"Running on hosts with kernel.pid_max raised above 2^31 (rare); loading recorded pids from a journal/log and re-enrolling them; parsing pids from untrusted input as u64/u32.","solutions":["Reduce kernel.pid_max (e.g. echo 4194304 > /proc/sys/kernel/pid_max) on hosts that set extreme values","Validate pid <= i32::MAX at the point the pid is captured from the OS/input","Never enroll pids read from stale logs; re-resolve the live process instead"],"exampleFix":"// before\nlet pg = ProcessGroup::new(recorded_pid as u32)?;\n// after\nif recorded_pid > i32::MAX as u64 {\n    return Err(anyhow!(\"stale pid {} exceeds i32::MAX\", recorded_pid));\n}\nlet pg = ProcessGroup::new(recorded_pid as u32)?;","handlingStrategy":"validation","validationCode":"fn pid_fits_i32(pid: u32) -> bool { pid <= i32::MAX as u32 }\nif !pid_fits_i32(pid) {\n    return Err(anyhow!(\"pid {pid} cannot be used with killpg\"));\n}","typeGuard":"fn pid_fits_i32(pid: u32) -> bool { pid <= i32::MAX as u32 }","tryCatchPattern":"if let Err(e) = ProcessGroup::new(pid) {\n    if e.kind() == io::ErrorKind::InvalidInput && pid > i32::MAX as u32 {\n        log::error!(\"stale/oversized pid {pid}; re-resolve the live process\");\n    }\n    return Err(e.into());\n}","preventionTips":["Validate pids read from journals/logs fit in i32 before use","Keep kernel.pid_max at or below i32::MAX on production hosts","Re-resolve pids from the live process table rather than replaying old values"],"tags":["process","unix","killpg","overflow","rust"],"backgroundTag":"invalid-process-group-id","analyzedSha":"bc7f02eddd3d84085849dc19ed216f11c23b0571","analyzedAt":"2026-08-31T04:59:42.031Z","schemaVersion":2},"datasetVersion":"2026-08-31T09:17:48.483Z"}