How to fix Error: Worker already listening on same port (cluster port conflict) in Node.js

Node.jsINTERMEDIATEMEDIUMUpdated Dec 22, 2025ยท 134 views

This error occurs when multiple cluster workers attempt to bind to the same port incorrectly, or when a worker tries to reopen a listener on a port it previously closed, causing EADDRINUSE conflicts in the cluster environment.

Quick fix

Fixes Error: Worker already listening on same port (cluster port conflict)

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isPrimary) {
  console.log(`Primary ${process.pid} is running`);

  // Fork workers
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died`);
  });
} else {
  // Workers share the same port
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('hello world\n');
  }).listen(8000);

  console.log(`Worker ${process.pid} started`);
}
  1. Verify your cluster implementation uses proper port sharing
  2. Add error handlers to catch port binding failures
  3. Avoid closing and reopening listeners in workers
  4. Use unique ports per worker if shared port is not needed
node.js โ€” error
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;
if (cluster.isPrimary) {
console.log(`Primary ${process.pid} is running`);
// Fork workers
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
cluster.on('exit', (worker, code, signal) => {
console.log(`Worker ${worker.process.pid} died`);
});
} else {
// Workers share the same port
http.createServer((req, res) => {
res.writeHead(200);
res.end('hello world\n');
}).listen(8000);
console.log(`Worker ${process.pid} started`);
}
Error: Worker already listening on same port (cluster port conflict)

What this error means

This error indicates a port binding conflict in Node.js cluster mode. While the cluster module is designed to allow multiple workers to share the same port through the primary process, this error occurs when workers attempt to manage port bindings incorrectly. In a properly configured cluster, when a worker calls server.listen(), the request is serialized and passed to the primary (master) process. The primary either returns an existing listening server handle or creates a new one. However, issues arise when workers try to close and reopen listeners on the same port, or when the port binding state becomes inconsistent between the primary and worker processes. A common scenario is when a worker closes a server and immediately tries to listen on the same port again. The primary process may return a cached file descriptor even if that descriptor has already produced an error, leading to EADDRINUSE errors or unpredictable behavior where the server binds to a random port instead of the intended one.

Typical symptoms

  • EADDRINUSE errors when workers attempt to listen on a port
  • Workers binding to random ports instead of the specified port
  • Error occurs when closing and reopening servers in cluster workers
  • Port conflicts only in cluster mode, not in single-process mode
  • Inconsistent behavior where some workers succeed and others fail

Common causes

  1. Worker attempts to close a server and immediately reopen it on the same port
  2. Primary process returns cached file descriptor that has already produced an error
  3. Race condition between server.close() completion and new server.listen() call
  4. Multiple workers attempting to manage their own port bindings instead of sharing through primary
  5. Incorrect cluster configuration where workers bypass primary process port sharing
  6. Delayed error reporting from libuv causing stale port binding state

How to fix "Error: Worker already listening on same port (cluster port conflict)"

1Verify your cluster implementation uses proper port sharing

Ensure workers are using the cluster module's built-in port sharing mechanism. Workers should all listen on the same port, with the primary process handling distribution:

javascript
const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isPrimary) {
  console.log(`Primary ${process.pid} is running`);

  // Fork workers
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`Worker ${worker.process.pid} died`);
  });
} else {
  // Workers share the same port
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('hello world\n');
  }).listen(8000);

  console.log(`Worker ${process.pid} started`);
}

All workers should call listen() on the same port - the primary process handles sharing.

2Add error handlers to catch port binding failures

Always add error event handlers to your server instances to properly catch and handle port-related errors:

javascript
const server = http.createServer((req, res) => {
  res.writeHead(200);
  res.end('hello world\n');
});

server.on('error', (err) => {
  if (err.code === 'EADDRINUSE') {
    console.error(`Port ${PORT} is already in use`);
    process.exit(1);
  } else {
    console.error('Server error:', err);
  }
});

server.listen(8000, () => {
  console.log(`Worker ${process.pid} listening on port 8000`);
});

This ensures errors are caught and logged instead of causing silent failures.

3Avoid closing and reopening listeners in workers

If you need to restart a server, restart the entire worker process instead of closing and reopening the listener:

javascript
// In primary process
cluster.on('message', (worker, message) => {
  if (message.cmd === 'restart') {
    console.log(`Restarting worker ${worker.id}`);
    worker.kill();
    cluster.fork();
  }
});

// In worker process - request restart instead of close/reopen
if (needsRestart) {
  process.send({ cmd: 'restart' });
}

This avoids the close/reopen race condition that causes cached file descriptor issues.

4Use unique ports per worker if shared port is not needed

If you don't need port sharing, assign unique ports to each worker based on worker ID:

javascript
if (cluster.isWorker) {
  const basePort = 8000;
  const workerPort = basePort + cluster.worker.id;

  http.createServer((req, res) => {
    res.writeHead(200);
    res.end(`Worker ${cluster.worker.id} on port ${workerPort}\n`);
  }).listen(workerPort);

  console.log(`Worker ${process.pid} listening on port ${workerPort}`);
}

This eliminates port sharing complexity entirely if it's not required for your use case.

5Implement graceful shutdown with proper cleanup

When shutting down workers, ensure proper cleanup sequencing to avoid port conflicts:

javascript
// In worker process
let server;

function startServer() {
  server = http.createServer((req, res) => {
    res.writeHead(200);
    res.end('hello world\n');
  });

  server.listen(8000);
}

function gracefulShutdown() {
  console.log(`Worker ${process.pid} shutting down`);

  if (server) {
    server.close(() => {
      console.log('Server closed');
      process.exit(0);
    });

    // Force shutdown after timeout
    setTimeout(() => {
      console.error('Forced shutdown');
      process.exit(1);
    }, 10000);
  } else {
    process.exit(0);
  }
}

process.on('SIGTERM', gracefulShutdown);
process.on('SIGINT', gracefulShutdown);

startServer();

Wait for server.close() to complete before restarting to ensure the port is fully released.

Advanced notes

Understanding Cluster Port Sharing

Node.js cluster uses two approaches for port sharing. On most platforms, it uses round-robin scheduling where the primary process listens on the port and distributes connections to workers. On Windows, it uses a shared socket handle approach. Understanding your platform's behavior helps debug port conflicts.

File Descriptor Caching

The primary process caches file descriptors for shared ports. When a worker calls listen(), the primary may return this cached descriptor even if it's stale or has errors. This is why close/reopen cycles fail - the cached descriptor represents the old, closed socket. The worker receives this stale descriptor and attempts to use it, leading to EADDRINUSE or random port binding.

Libuv Delayed Error Reporting

Port binding errors may not be reported immediately due to libuv's asynchronous nature. A worker might believe it successfully bound to a port when the actual bind() operation hasn't completed or has failed. This timing issue is exacerbated in cluster mode where the primary process intermediates all port operations.

UDP vs TCP

The cluster module only supports TCP port sharing, not UDP. Attempting to share UDP ports across workers will fail. Each UDP server needs its own unique port or you must implement a custom load balancing solution at the application level.

Worker Restart Strategies

For production systems using process managers like PM2 or cluster managers, configure zero-downtime restarts by starting new workers before killing old ones. This prevents port binding issues during deployments and ensures at least one worker is always available to handle the shared port.

Frequently asked questions

What does "Error: Worker already listening on same port (cluster port conflict)" mean?
js cluster mode. While the cluster module is designed to allow multiple workers to share the same port through the primary process, this error occurs when workers attempt to manage port bindings incorrectly. listen(), the request is serialized and passed to the primary (master) process.
How do I fix "Error: Worker already listening on same port (cluster port conflict)"?
This error occurs when multiple cluster workers attempt to bind to the same port incorrectly, or when a worker tries to reopen a listener on a port it previously closed, causing EADDRINUSE conflicts in the cluster environment.
What causes "Error: Worker already listening on same port (cluster port conflict)"?
Worker attempts to close a server and immediately reopen it on the same port Primary process returns cached file descriptor that has already produced an error Race condition between server.close() completion and new server.listen() call
Is the "Error: Worker already listening on same port (cluster port conflict)" error serious?
It is a medium-severity error โ€” more of a blocker than a risk. The steps above resolve it.

Official resources & further reading