This error occurs when attempting to kill a process that no longer exists or never existed. The ESRCH code indicates that the specified process ID (PID) cannot be found in the system.
The ESRCH error (Error: kill ESRCH) stands for "Error: no such process" and is thrown by Node.js when calling `process.kill()` or `subprocess.kill()` on a process ID that doesn't exist in the system. This error is part of Node.js's process management API and indicates that the system cannot find a process with the given PID. The error can occur with both the parent process and child processes spawned via the `child_process` module. ESRCH is a POSIX error code that Node.js surfaces when the underlying system call to terminate a process fails because the target process cannot be located. This commonly happens in asynchronous environments where process lifecycles are managed across multiple event loop iterations.
Use process.kill(pid, 0) to test if a process exists without actually sending a kill signal. This method returns true if the process exists, or throws ESRCH if it doesn't:
function isProcessRunning(pid) {
try {
process.kill(pid, 0);
return true;
} catch (err) {
return err.code !== 'ESRCH';
}
}
// Use before killing
if (isProcessRunning(childPid)) {
process.kill(childPid, 'SIGTERM');
}This prevents the error by verifying the process exists before attempting termination.
Handle the ESRCH error gracefully instead of letting it crash your application:
try {
process.kill(pid, 'SIGTERM');
console.log(`Process ${pid} killed successfully`);
} catch (err) {
if (err.code === 'ESRCH') {
console.log(`Process ${pid} already terminated`);
} else {
throw err; // Re-throw unexpected errors
}
}This is especially important in cleanup handlers and shutdown sequences where processes may have already exited.
Listen to the 'exit' event on child processes to track their lifecycle and avoid killing already-exited processes:
const { spawn } = require('child_process');
const child = spawn('node', ['script.js']);
let childExited = false;
child.on('exit', (code, signal) => {
childExited = true;
console.log(`Child process exited with code ${code}`);
});
// Later in cleanup
function cleanup() {
if (!childExited) {
try {
child.kill('SIGTERM');
} catch (err) {
if (err.code !== 'ESRCH') throw err;
}
}
}Tracking process state prevents race conditions where the process exits between event loop ticks.
Node.js 15+ supports AbortController for more reliable process cancellation:
const { spawn } = require('child_process');
const controller = new AbortController();
const { signal } = controller;
const child = spawn('node', ['long-running.js'], { signal });
// Abort cleanly without worrying about ESRCH
setTimeout(() => {
controller.abort(); // Handles termination safely
}, 5000);
child.on('error', (err) => {
if (err.name === 'AbortError') {
console.log('Process aborted successfully');
}
});This modern API handles edge cases internally and prevents ESRCH errors from surfacing.
Windows-specific behavior: On Windows, process.kill() throws ESRCH when attempting to kill process groups using negative PIDs (e.g., process.kill(-pid)). This works on Unix-like systems but is unsupported on Windows. Use the tree-kill package for cross-platform process tree termination.
Shell wrapper PIDs: When spawning child processes with { shell: true }, the PID returned by Node.js refers to the shell wrapper (sh, cmd.exe), not the actual command. The child process may continue running even after killing the shell. Use { shell: false } when possible or use process tree killing libraries.
PM2 and cluster mode: In cluster mode with PM2 or Node.js cluster module, workers may exit independently, causing the master process to encounter ESRCH when broadcasting kill signals. Implement worker tracking and remove PIDs from the pool immediately upon exit events.
Process.kill() signal 0: Sending signal 0 (process.kill(pid, 0)) is the standard POSIX way to test process existence. It's atomic and reliable but requires appropriate permissions. On Windows, it may return false positives for processes owned by other users.
Race conditions in tests: This error frequently appears in test suites that rapidly spawn and kill processes. Add small delays or use Promise-based process managers that properly await process termination before continuing.
Error: Listener already called (once event already fired)
EventEmitter listener already called with once()
Error: EACCES: permission denied, open '/root/file.txt'
EACCES: permission denied
Error: Invalid encoding specified (stream encoding not supported)
How to fix Invalid encoding error in Node.js readable streams
Error: EINVAL: invalid argument, open
EINVAL: invalid argument, open
TypeError: readableLength must be a positive integer (stream config)
TypeError: readableLength must be a positive integer in Node.js streams