This error occurs when you call server.listen() more than once on the same server instance. Once a server is listening on a port, you cannot call listen() again without closing it first, as the port binding is already established.
When you create a Node.js HTTP server using `http.createServer()` or Express `app.listen()`, the server object can only be actively listening on a port once. Attempting to call the `listen()` method again on the same server instance while it's already listening throws an error. This is a fundamental constraint of the Node.js server lifecycle. A single server instance maintains one active port binding at a time. If you try to transition the server to a listening state again without first closing it, the operating system's socket binding rules prevent this operation, and Node.js raises an error to alert you to this programming mistake. This is different from EADDRINUSE (address already in use), which occurs when a completely different process holds the port. This error is about the same server object being told to listen multiple times.
Search your codebase for all instances of .listen( to ensure you are not calling it multiple times on the same server.
// ❌ Wrong - listen() called twice
const server = app.listen(3000);
server.listen(3000); // Error!
// ✅ Correct - listen() called once
const server = app.listen(3000);Check these common locations:
- Main application entry point (index.js, server.js)
- Test setup files (jest.setup.js, test configuration)
- Module initialization code (code that runs at import time)
- Middleware or route handlers (should not contain listen() calls)
- HMR or development tooling configuration
If you need to stop and restart the server (for example in tests), always close the server before creating a new listen() call:
// Close the existing server
if (server) {
await new Promise<void>((resolve, reject) => {
server.close((err) => {
if (err) reject(err);
else resolve();
});
});
}
// Now you can create a new listen() call
const newServer = app.listen(3000);Or use the server property directly:
const server = app.listen(3000);
// Later, close it
await new Promise<void>((resolve) => {
server.close(() => resolve());
});
// Now you can call listen() again on a new instance
const newServer = app.listen(3000);If your code initializes the server in multiple places, use a singleton pattern to ensure the server is only created and listening once:
let serverInstance = null;
async function getServer() {
if (serverInstance === null) {
serverInstance = app.listen(3000, () => {
console.log('Server started on port 3000');
});
}
return serverInstance;
}
// Always use getServer() instead of calling listen() directly
const server = await getServer();
const server2 = await getServer(); // Returns the same instanceThis ensures listen() is only called once, regardless of how many times the initialization code runs.
If using development tools with hot reloading, prevent duplicate listen() calls by checking if the server is already active:
// In your module that sets up the server
if (import.meta.hot) {
import.meta.hot.dispose(() => {
// Cleanup code runs when the module is replaced
server.close();
});
}
// Only call listen() if not already listening
if (!server.listening) {
server.listen(3000);
}Or with CommonJS/Node.js:
// Check if module is being reloaded
if (module.hot) {
module.hot.dispose((data) => {
if (server) {
server.close();
}
});
}
// Only listen once
if (!server || !server.listening) {
server = app.listen(3000);
}In test files, ensure you are not calling listen() multiple times. Use beforeAll() and afterAll() hooks properly:
// ❌ Wrong - listen() called in multiple places
describe('API Tests', () => {
beforeEach(() => {
server = app.listen(3000); // Called multiple times!
});
test('GET /health', () => {
// ...
});
});
// ✅ Correct - listen() called once per test suite
describe('API Tests', () => {
let server;
beforeAll(() => {
server = app.listen(3000); // Called once
});
afterAll((done) => {
server.close(done); // Properly closed after tests
});
test('GET /health', () => {
// ...
});
});Add event listeners to detect if the server is already listening or if an error occurs:
const server = app.listen(3000);
server.on('listening', () => {
console.log('Server is listening on port 3000');
});
server.on('error', (err) => {
if (err.code === 'ERR_SERVER_ALREADY_LISTENING') {
console.error('Server is already listening. Close it first before calling listen() again.');
process.exit(1);
} else {
throw err;
}
});This helps you detect and handle the situation gracefully with clear error messages.
Server Instance Lifecycle:
A Node.js HTTP server instance goes through several states: created, listening, closed, and destroyed. Once the server transitions to "listening", it cannot accept another .listen() call until it has transitioned to "closed". This is enforced by the Node.js runtime and the underlying operating system socket layer.
Difference from EADDRINUSE:
EADDRINUSE occurs when the operating system refuses to bind a port because another process (any process) is already bound to it. "Server already listening" is an application-level error that happens when you try to call .listen() on a server instance that is already in a listening state. The distinction is important: EADDRINUSE is about external processes, while this error is about your own code trying to reuse a server instance incorrectly.
Server Reuse Patterns:
If you need to restart a server during testing or in a long-running application, create a new server instance rather than trying to call .listen() again on the existing one. Alternatively, if you want to change the port, close the server first, then create a new one listening on the new port.
Express.js Behavior:
Express's app.listen() is a convenience method that internally creates an HTTP server and calls .listen() on it. Calling app.listen() multiple times creates multiple server instances and calls .listen() on each, which is the correct behavior. However, calling .listen() directly on the server returned by a previous app.listen() call will trigger this error.
Debugging Tips:
Use the Node.js debugger or console logs before each .listen() call to trace the code path and identify where the duplicate call is happening. In async code, ensure proper error handling and promise resolution to avoid unexpected re-executions of initialization code.
Production Implications:
This error should never occur in production code, as it indicates a programming error in your initialization logic. If it does occur, it points to a serious issue with your application's startup sequence. Always run comprehensive tests (particularly integration tests that exercise the full server lifecycle) to catch this error before deploying.
Error: EMFILE: too many open files, watch
EMFILE: fs.watch() limit exceeded
Error: Middleware next() called multiple times (next() invoked twice)
Express middleware next() called multiple times
Error: Worker failed to initialize (worker startup error)
Worker failed to initialize in Node.js
Error: EMFILE: too many open files, open 'file.txt'
EMFILE: too many open files
Error: cluster.fork() failed (cannot create child process)
cluster.fork() failed - Cannot create child process