Node.jsRunbook 0/4 done
EADDRINUSE

Node.js Error EADDRINUSE: Address already in use

Error✕ Not retryable · fix the payloadRuntime
TL;DR · 10-second read

Another process already listens on that port, often a previous dev server that did not exit. Kill it (lsof -ti :3000 | xargs kill) or use a different PORT, and close the server on SIGTERM.

Identify: does your log match?

What you see · exact log / response
node:events:497
      throw er; // Unhandled 'error' event
      ^

Error: listen EADDRINUSE: address already in use :::3000
    at Server.setupListenHandle [as _listen2] (node:net:1904:16)
    at listenInCluster (node:net:1952:12)
    at Server.listen (node:net:2063:7) {
  code: 'EADDRINUSE',
  errno: -98,
  syscall: 'listen',
  address: '::',
  port: 3000
}
  1. High

    Orphaned previous dev server

    A crashed terminal, nodemon restart or IDE run left the old process alive and holding the port.

  2. Medium

    listen() called twice

    Importing the app module twice, or calling app.listen in both server.ts and a test, binds the same port twice in one process.

  3. Medium

    Another service owns the port

    macOS AirPlay Receiver uses 5000 and 7000; Docker containers publish ports on the host.

Fix

Find and stop the process holding the port

✕ Broken · CLI
npm run dev   # EADDRINUSE again
✓ Fixed · CLI
lsof -nP -iTCP:3000 -sTCP:LISTEN
kill $(lsof -ti tcp:3000)        # SIGTERM; use kill -9 only if it ignores it
# Windows: netstat -ano | findstr :3000  then  taskkill /PID <pid> /F

lsof shows the PID and command name so you do not kill the wrong process.

Verify: reproduce it on purpose

Reproduce locally · node
$ node -e "const n=require('net');n.createServer().listen(3000,()=>n.createServer().listen(3000).on('error',e=>{console.log(e.code);process.exit()}))"

Run it against a dev environment to trigger EADDRINUSE on purpose and test your error handler.

Prevent

  • Read PORT from env.
  • Use supertest(app) instead of listening in tests.
  • Handle SIGTERM in every long-running process.

FAQ

Why is port 5000 taken on my Mac?

macOS Monterey+ runs AirPlay Receiver on 5000 and 7000. Disable it in System Settings > General > AirDrop & Handoff or use another port.

Can I make the OS pick a free port?

Yes, listen(0) binds a random free port; read it with server.address().port.

What does ::: in "address already in use :::3000" mean?

It is the IPv6 wildcard :: followed by :3000, meaning Node tried to listen on all interfaces.

Related errors

Last verified 2026-10-20 · Source: POSIX errno + Node.js ERR_* codes (doc/api/errors.md) · Official docs ↗ · ~22,200 searches/mo