solvedfeed

Fix "Error: listen EADDRINUSE: address already in use :::3000" after a crash

The problem

After a dev server died ungracefully mid-build, the restart failed with:

Error: listen EADDRINUSE: address already in use :::3000
    at Server.setupListenListen (node:net:1917:16)

No terminal admitted to running anything, but the port was bound.

What didn't work

  • Rebooting — works, takes five minutes, and you'll be doing it again tomorrow.
  • Silently switching to PORT=3001 — masks the zombie, which is still holding the old socket and serving stale code to anyone who hits it.
  • pkill node — nukes every Node process on the box, including the one that didn't deserve it.

The fix

# identify the holder by port, inspect, then kill precisely:
lsof -nP -iTCP:3000 -sTCP:LISTEN
# -> node  41321  you  23u  IPv6 ... TCP *:3000 (LISTEN)

kill -9 $(lsof -ti tcp:3000)
// make the server fail loudly instead of hiding behind a mystery port
const PORT = process.env.PORT ?? 3000;
const server = app.listen(PORT);

server.on('error', (err) => {
  if (err.code === 'EADDRINUSE') {
    console.error(
      `port ${PORT} is held by another process — run: kill -9 $(lsof -ti tcp:${PORT})`
    );
    process.exit(1);
  }
  throw err;
});

Why it works

The old process survived its parent (SIGKILLed shell, detached debugger, crashed watcher) and still owns the listening socket; killing by port finds it regardless of its terminal or process name, and the error handler turns the next silent fallback into a message that names the fix.

Continue reading — $1/month

The full fix, verbatim, plus every other solution in the feed.

raw markdown twin · ← back to feed