Node.js
Node.js — EADDRINUSE: address already in use
Written and reviewed by Sahil Srivastav
Error: listen EADDRINUSE: address already in use :::3000What this error actually means
The operating system rejected a request to bind a listening socket because the requested address and port conflict with an existing binding. In the example, :::3000 is an IPv6 wildcard address on port 3000. Depending on platform configuration, a wildcard IPv6 listener may also cover IPv4 connections, so apparently different address strings do not necessarily mean separate available endpoints.
The important unit is the network namespace and binding, not the project directory. Two terminal windows, a service manager and a container port publication can all contend for the same host port. Conversely, two containers can listen on the same internal port without conflict when each has its own namespace.
This error occurs before the new server accepts traffic. It is not caused by HTTP route registration or a slow request handler. Identify who owns the binding and why a second owner started; repeatedly choosing another port can conceal a broken lifecycle that later affects deployments and tests.
Causes, most common first
- 1An earlier process still owns the listener. A forgotten development server, orphaned child process or independently managed service is still running. The parent terminal closing does not prove the child stopped. Inspect process ancestry and command line before terminating anything, particularly on a shared workstation or host.
- 2Application startup creates two independent servers. Importing a module that calls listen can unexpectedly start a server during tests or worker initialisation. A second bootstrap then creates another server on the same address. Calling listen twice on the same already-listening Server can instead produce ERR_SERVER_ALREADY_LISTEN; inspect the exact error.
- 3Test cleanup does not await server closure. The next test binds a fixed port before the previous server has closed its listener. Persistent client connections can complicate shutdown. Parallel test processes multiply the problem because each assumes exclusive ownership of the same port.
- 4Wildcard binding or host-port publication overlaps. Binding 0.0.0.0 claims more than one interface. Another service bound to a specific address may conflict, and IPv6 dual-stack behaviour can add overlap. With containers, inspect the host publication separately from the application’s internal listen port.
When you see it
- The development server exits immediately while an older instance still answers requests
- Tests pass individually but fail when suites start servers in parallel
- A restart loop continually reports the same port conflict
- A container listens internally but publishing its port on the host fails
How to diagnose it
Step 1
Find the actual listening process
On macOS or Linux with lsof installed, this displays processes listening on the example port without resolving names. Permissions can hide other users’ details; an empty result from a restricted account is not proof that the port is free.
lsof -nP -iTCP:3000 -sTCP:LISTENStep 2
Inspect the binding on Linux
Check the local address as well as the port. Run inside the same namespace as the failing process when investigating a container. Process details may require suitable privileges.
ss -ltnp 'sport = :3000'Step 3
Establish process ownership before stopping it
Use the PID reported by the socket tool and inspect its parent, start time and command. A service manager may immediately restart a process killed directly; stop or reconfigure the owning service instead of fighting the supervisor.
ps -p <pid> -o pid,ppid,lstart,argsStep 4
Search for implicit startup
Inspect every listen call and executable entry point. Separate module import from process startup so tests and workers can construct the application without automatically taking a port.
rg -n "\.listen\(|createServer\(" src test testsThe fix
If a stale process belongs to this application, stop it through its normal shutdown path or service manager and confirm the listener disappears. Do not pipe arbitrary port owners into a kill command; the process may be a database proxy or another developer’s service.
Export an application or server factory without side effects, and call listen only from the executable bootstrap. Log the resolved address once startup succeeds so duplicate initialisation becomes visible. Attach an error handler before listening and report startup failure clearly to the supervisor.
In tests, bind port 0 to ask the kernel for an available port, then read server.address().port after the listening event. Await server closure during teardown and stop test clients that keep connections alive. This removes fixed-port contention while preserving explicit lifecycle ownership.
For deployment, assign host ports deliberately or put replicas behind the intended orchestrator networking abstraction. Change the binding only when it matches the architecture; binding a service to all interfaces just to evade a local-address mistake can unintentionally expose it.
import { createServer } from "node:http";
import { once } from "node:events";
const server = createServer((req, res) => res.end("ok"));
server.listen(0, "127.0.0.1");
await once(server, "listening");
const address = server.address();
console.log(`test port: ${address.port}`);
// After the test has finished its requests:
await new Promise((resolve, reject) => {
server.close(error => error ? reject(error) : resolve());
});How to stop it coming back
- Keep listen calls out of modules imported by tests and workers
- Use kernel-assigned ports for isolated tests and await lifecycle events
- Record the process manager and port owner in the development runbook
- Verify wildcard and container host-port behaviour in the target environment
FAQ
Should I kill whatever uses port 3000?
First identify the process and its owner. Stop a stale instance of your application deliberately. A blind kill can interrupt an unrelated service, and a supervisor may recreate it immediately anyway.
Does TIME_WAIT mean my server still owns the port?
A TIME_WAIT entry is different from a listening socket. Start by filtering for LISTEN and inspecting bindings. If no listener exists, investigate bind address, namespace and platform socket rules rather than assuming every connection using that port is a server.
Why do two containers use port 3000 successfully?
Their internal network namespaces can each own that port. Publishing both as the same host address and port creates a separate conflict at the host boundary. Inspect internal and published ports independently.
Related
Other errors engineers hit next to this one
- Too many open files
- Out of memory: Killed process
- No space left on device despite free disk space
- Text file busy during executable replacement
- set -e script continues after a failed pipeline
- An unquoted variable turns one argument into several
- 502 Bad Gateway from a reverse proxy
- 504 Gateway Timeout