How to fix Error: kill ESRCH in Node.js

Node.jsINTERMEDIATELOWUpdated Dec 9, 2025ยท 219 views

The ESRCH error occurs when attempting to send a signal to a process that no longer exists. This typically happens with process.kill() or child process operations when the target process has already exited.

Quick fix

Fixes ESRCH

try {
  // Signal 0 checks existence without killing
  process.kill(pid, 0);
  console.log('Process exists');

  // Now safe to kill
  process.kill(pid, 'SIGTERM');
} catch (err) {
  if (err.code === 'ESRCH') {
    console.log('Process already exited');
  } else {
    throw err; // Re-throw other errors
  }
}
  1. Check if process exists before killing
  2. Wrap kill calls in try-catch blocks
  3. Handle child process errors properly
  4. Track process state to avoid stale PIDs
node.js โ€” error
try {
// Signal 0 checks existence without killing
process.kill(pid, 0);
console.log('Process exists');
// Now safe to kill
process.kill(pid, 'SIGTERM');
} catch (err) {
if (err.code === 'ESRCH') {
console.log('Process already exited');
} else {
throw err; // Re-throw other errors
}
}
Error: kill ESRCH

What this error means

The ESRCH error (Error: kill ESRCH) stands for "Error: No Such Process". This error is thrown by Node.js when you attempt to send a signal (such as SIGTERM or SIGKILL) to a process ID that does not exist or is no longer running. This commonly occurs when using process.kill() or childProcess.kill() methods. The error indicates that the operating system cannot find the process with the specified PID, usually because the process has already terminated before the signal could be delivered. The ESRCH error is particularly common in scenarios involving child processes, process managers, and automated cleanup routines where timing issues can cause a process to exit between the time you check for it and when you attempt to kill it.

Typical symptoms

  • process.kill() throws an error when attempting to terminate a process
  • Child process cleanup fails with "kill ESRCH" message
  • Process managers like PM2 report ESRCH errors when stopping workers
  • CI/CD pipelines fail during cleanup phases with ESRCH errors
  • Windows systems show higher frequency of this error compared to Unix-like systems
  • Error occurs intermittently during application shutdown sequences

Common causes

  1. Process has already exited before kill() is called, creating a race condition
  2. Invalid or stale PID being used to reference a process that no longer exists
  3. Windows-specific issues where PIDs are assigned differently than expected
  4. Attempting to kill a process group with negative PID on Windows (not supported)
  5. Multiple kill attempts on the same process without checking if previous call succeeded
  6. Child process exits naturally while parent is attempting cleanup
  7. Using outdated PID after process has been respawned or restarted

How to fix "Error: kill ESRCH"

1Check if process exists before killing

Use signal 0 to test if a process exists without actually sending a kill signal:

javascript
try {
  // Signal 0 checks existence without killing
  process.kill(pid, 0);
  console.log('Process exists');

  // Now safe to kill
  process.kill(pid, 'SIGTERM');
} catch (err) {
  if (err.code === 'ESRCH') {
    console.log('Process already exited');
  } else {
    throw err; // Re-throw other errors
  }
}

Note that there's still a small race condition window between checking and killing, but this reduces the likelihood significantly.

2Wrap kill calls in try-catch blocks

Always handle the ESRCH error gracefully when killing processes:

javascript
function killProcessSafely(pid, signal = 'SIGTERM') {
  try {
    process.kill(pid, signal);
    console.log(`Successfully sent ${signal} to process ${pid}`);
    return true;
  } catch (err) {
    if (err.code === 'ESRCH') {
      // Process already exited - not an error
      console.log(`Process ${pid} already exited`);
      return false;
    } else if (err.code === 'EPERM') {
      console.error(`No permission to kill process ${pid}`);
      throw err;
    } else {
      throw err;
    }
  }
}

This approach treats ESRCH as expected behavior rather than an error.

3Handle child process errors properly

When working with child processes, always listen for error events:

javascript
const { spawn } = require('child_process');

const child = spawn('node', ['script.js']);

child.on('error', (err) => {
  console.error('Failed to start or kill child process:', err);
});

child.on('exit', (code, signal) => {
  console.log(`Child exited with code ${code} and signal ${signal}`);
});

// Safe cleanup
function cleanup() {
  if (child && !child.killed) {
    try {
      child.kill('SIGTERM');
    } catch (err) {
      if (err.code !== 'ESRCH') {
        console.error('Error killing child:', err);
      }
    }
  }
}

process.on('exit', cleanup);
process.on('SIGINT', cleanup);

This ensures errors are caught and handled appropriately.

4Track process state to avoid stale PIDs

Maintain state tracking for processes you manage:

javascript
class ProcessManager {
  constructor() {
    this.processes = new Map();
  }

  spawn(id, command, args) {
    const child = spawn(command, args);

    this.processes.set(id, {
      pid: child.pid,
      process: child,
      alive: true
    });

    child.on('exit', () => {
      const proc = this.processes.get(id);
      if (proc) proc.alive = false;
    });

    return child;
  }

  kill(id, signal = 'SIGTERM') {
    const proc = this.processes.get(id);

    if (!proc) {
      console.log(`No process with id ${id}`);
      return false;
    }

    if (!proc.alive) {
      console.log(`Process ${id} already exited`);
      return false;
    }

    try {
      proc.process.kill(signal);
      return true;
    } catch (err) {
      if (err.code === 'ESRCH') {
        proc.alive = false;
        return false;
      }
      throw err;
    }
  }
}

This approach tracks whether processes are still alive before attempting to kill them.

5Use graceful shutdown patterns

Implement proper shutdown sequences with timeouts:

javascript
async function gracefulShutdown(child, timeout = 5000) {
  return new Promise((resolve) => {
    let killed = false;

    const timer = setTimeout(() => {
      if (!killed && !child.killed) {
        try {
          console.log('Force killing process...');
          child.kill('SIGKILL');
        } catch (err) {
          if (err.code !== 'ESRCH') {
            console.error('Error force killing:', err);
          }
        }
      }
      resolve();
    }, timeout);

    child.on('exit', () => {
      killed = true;
      clearTimeout(timer);
      resolve();
    });

    try {
      child.kill('SIGTERM');
    } catch (err) {
      if (err.code === 'ESRCH') {
        killed = true;
        clearTimeout(timer);
        resolve();
      } else {
        throw err;
      }
    }
  });
}

// Usage
await gracefulShutdown(child, 5000);
console.log('Process shut down successfully');

This gives processes time to exit gracefully before force-killing.

Advanced notes

Windows-specific considerations: Windows handles process signals differently than Unix-like systems. The kill() method on Windows provides emulated signal behavior, but has limitations:

- Windows does not support killing process groups with negative PIDs
- PIDs reported by Node.js may not match those shown in Task Manager
- SIGTERM and SIGKILL are treated identically on Windows (both terminate immediately)
- The node-pty and similar libraries often encounter ESRCH on Windows due to PID handling differences

Race conditions: The ESRCH error is fundamentally a race condition issue. Even with signal 0 checks, there's a tiny window where a process can exit between checking and killing. For critical applications, implement proper state tracking rather than relying solely on PID checks.

Process managers: Tools like PM2, Forever, and Nodemon handle ESRCH internally and typically don't propagate these errors to users. If you're building your own process manager, follow their pattern of treating ESRCH as informational rather than a fatal error.

Signal delivery guarantees: POSIX systems don't guarantee signal delivery if a process exits before the signal arrives. Your code should always assume that kill() might fail due to timing, and handle it gracefully.

Alternative approaches: Consider using IPC (Inter-Process Communication) channels with child processes instead of relying on signals. This allows for graceful shutdown requests that the child can acknowledge, reducing the need for forced kills.

Frequently asked questions

What does "ESRCH" mean?
The ESRCH error (Error: kill ESRCH) stands for "Error: No Such Process". js when you attempt to send a signal (such as SIGTERM or SIGKILL) to a process ID that does not exist or is no longer running. kill() methods.
How do I fix "ESRCH"?
The ESRCH error occurs when attempting to send a signal to a process that no longer exists. This typically happens with process.kill() or child process operations when the target process has already exited.
What causes "ESRCH"?
Process has already exited before kill() is called, creating a race condition Invalid or stale PID being used to reference a process that no longer exists Windows-specific issues where PIDs are assigned differently than expected
Is the "ESRCH" error serious?
It is a low-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading