ClementTsang/bottom · error
Error code
Error message
Error code {err_code} - {err} What it means
On Unix, the public `kill_process_given_pid(pid, signal)` calls `libc::kill`. On failure (non-zero return) it reads the last OS error and bails with `Error code {err_code} - {err}` where `err` is a human-readable description of the errno (ESRCH, EPERM, or EINVAL). The numeric errno accompanies the message because any libc error beyond the three mapped cases also lands here with the generic 'Unknown error occurred.' text.
Solutions
- Match on the errno shown in the message: 3 (ESRCH) means the process is already gone — treat as success; 1 (EPERM) means run as root/sudo or fix ownership; 22 (EINVAL) means pass a valid signal number
- Verify the PID is still alive before killing
- If EINVAL, pass a valid signal (e.g. 9 for SIGKILL, 15 for SIGTERM)
- Check container capabilities (CAP_KILL) or user namespaces if EPERM occurs inside Docker/Kubernetes
Example fix
// before
kill_process_given_pid(pid, signal)?;
// after
match kill_process_given_pid(pid, signal) {
Ok(()) => {},
Err(e) if e.to_string().contains("Error code 3") => {
// ESRCH: process already gone, ignore
},
Err(e) => return Err(e),
} Defensive patterns
Strategy: try-catch
Validate before calling
// Unix: validate signal and liveness before libc::kill
assert!((1..=31).contains(&signal), "invalid signal {signal}");
// ESRCH check: kill(pid, 0) probes existence without sending a signal
let alive = unsafe { libc::kill(pid, 0) } == 0
|| std::io::Error::last_os_error().raw_os_error() != Some(libc::ESRCH); Type guard
fn errno_of(err: &anyhow::Error) -> Option<i32> {
err.chain().find_map(|c|
c.downcast_ref::<std::io::Error>().and_then(|e| e.raw_os_error()))
}
fn is_esrch(err: &anyhow::Error) -> bool { errno_of(err) == Some(libc::ESRCH) } Try / catch
match kill_process_given_pid(pid, signal) {
Ok(()) => {}
Err(e) if e.to_string().contains("Error code 3") => {} // ESRCH: gone
Err(e) if e.to_string().contains("Error code 1") => {
eprintln!("need elevated privileges: {e}") // EPERM
}
Err(e) => return Err(e),
} Prevention
- Probe with kill(pid, 0) before sending a real signal
- Pass only valid signal numbers (SIGKILL=9, SIGTERM=15)
- Run as root or with CAP_KILL when targeting other users' processes
- Map errnos 3/1/22 to distinct handling paths instead of one generic failure
When it happens
Trigger: `libc::kill` returning -1: ESRCH (target PID does not exist), EPERM (insufficient permission to signal the target), EINVAL (invalid signal value passed as `signal`), or any other errno (e.g. EPERM in containers, init restrictions) with a known code.
Common situations: Killing a stale PID after the process exited (ESRCH); non-root user killing another user's process (EPERM); passing an out-of-range signal number like 99 (EINVAL); running inside Docker without CAP_KILL.
Understand the failure class
Background: Permission denied / not authorized / 403 Forbidden: access-control rejections when the caller lacks the required role, grant, or ownership — this error's family across 18 libraries.
Related errors
- Error code unknown
- statvfs failed to get the disk usage for disk
- failed to get process for pid
- process may have already been terminated.
AI-assisted analysis of ClementTsang/bottom@b77d317502 (2026-09-07).
Data as JSON: /api/errors/2217f6600cf3fe84.
Report an issue: GitHub.
Appendix: source
Thrown at src/utils/process_killer.rs:81
pub fn kill_process_given_pid(pid: Pid, signal: usize) -> anyhow::Result<()> {
// SAFETY: the signal should be valid, and we act properly on an error (exit
// code not 0).
let output = unsafe { libc::kill(pid, signal as i32) };
if output != 0 {
// We had an error...
let err_code = std::io::Error::last_os_error().raw_os_error();
let err = match err_code {
Some(libc::ESRCH) => "the target process did not exist.",
Some(libc::EPERM) => {
"the calling process does not have the permissions to terminate the target process(es)."
}
Some(libc::EINVAL) => "an invalid signal was specified.",
_ => "Unknown error occurred.",
};
if let Some(err_code) = err_code {
bail!(format!("Error code {err_code} - {err}"))
} else {
bail!(format!("Error code unknown - {err}"))
};
}
Ok(())
}
View on GitHub (pinned to b77d317502)