Fix EADDRINUSE: Address Already in Use in Node.js

Quick answer

Node.js throws EADDRINUSE when another listener already owns the requested address and port, such as :::3000. Identify the owner before stopping it, then either shut down the stale process, fix a duplicate server.listen call, or choose a deliberate host port. Treat Docker, WSL, tests, CI, and production as separate binding layers.

You start a Node.js server and receive:

Error: listen EADDRINUSE: address already in use :::3000

This is an operating-system bind failure, not an HTTP, npm, Express, or Next.js failure. Node asked the kernel to reserve an address and port; the kernel found an existing owner and refused. The fast fix may be to stop a stale development server. The durable fix is to prove who owns the socket and address the layer that created the collision.

That distinction matters. Killing every Node process can interrupt a database proxy, another checkout, or a colleague's shared service. Switching every app to a new number only hides a duplicate listen() call. The sections below walk through safe diagnosis first, then framework, Docker, WSL, CI, and production fixes.

Quick Answer

Node.js throws EADDRINUSE when another listener already owns the requested address and port, such as :::3000. Identify the owner before stopping it, then either shut down the stale process, fix a duplicate server.listen call, or choose a deliberate host port. Treat Docker, WSL, tests, CI, and production as separate binding layers.

TL;DR

  • EADDRINUSE means an address-and-port bind was rejected because it is already in use.
  • :::3000 is an IPv6 all-interfaces bind. It may also occupy IPv4 port 3000 through dual-stack behavior.
  • Inspect the listener and command line before you stop anything.
  • A second app.listen() or server.listen() is a code bug, not a port-choice problem.
  • In Docker, 3000:3000 claims a host port; the container's internal port is not the conflicting resource.
  • Use port: 0 in parallel tests. Let the OS choose a free port and read it from server.address().
  • In production, fail clearly or use platform-assigned PORT. Do not loop forever retrying a port that belongs to another deployed service.

Symptoms

The exact address changes with the host and runtime, but the failure has the same meaning:

SymptomWhat Node tried to bindLikely layer
address already in use :::3000IPv6 unspecified address, TCP 3000Local dev server, dual-stack collision
address already in use 0.0.0.0:3000All IPv4 interfaces, TCP 3000Another host-level listener
address already in use 127.0.0.1:3000Local loopback only, TCP 3000Local tool or test server
Docker Bind for 0.0.0.0:3000 failedDocker host-port publicationContainer or host service
Tests fail only in CI or parallel modeA shared hard-coded test portTest worker/process leak
Server starts once, then crashes during reloadA second bootstrap path calls listenApp lifecycle or watcher bug

This error happens before a client can connect. A browser showing ECONNREFUSED means no process accepted the connection; EADDRINUSE means your new process could not start accepting connections at all.

Common Causes

CauseWhy it creates a collisionBest fix
A stale npm run dev processThe old process is still listening after a terminal or editor changeIdentify it, stop it gracefully, verify the port is free
Two terminals start the same appBoth request the same default portKeep one instance or give each checkout a defined port
Duplicate listen() callsTwo server objects in one app claim the same portKeep one process-level listener
Docker ports: ["3000:3000"]Docker claims host port 3000Stop the owning container or map a different host port
WSL or desktop port forwardingWindows and the Linux VM expose related localhost portsInspect both Windows and WSL listeners
Parallel testsEach worker binds a fixed portUse port 0 and close every server
CI jobs sharing a hostConcurrent jobs use a static portIsolate jobs or allocate a dynamic port
Cloud runtime PORT is ignoredThe platform expects one assigned listenerBind process.env.PORT and the required host
A process manager restarts an old releaseTwo process groups overlap during deployUse the manager's handoff or rolling-deploy behavior

Root Cause: A Bind Is Exclusive

A TCP listener is identified by more than a number. The kernel considers the protocol, local address, port, and platform-specific socket options. In the ordinary Node.js server case, only one process can listen on the same effective address and TCP port.

Node's server.listen() is asynchronous. A successful bind produces the listening event. When another server already owns the requested port/address/handle, Node emits EADDRINUSE instead. The Node documentation also notes that calling listen() again on the same server before close() raises ERR_SERVER_ALREADY_LISTEN—a useful clue when the duplication occurs inside one process.

How Node.js EADDRINUSE occurs when two listeners request TCP port 3000A running server already owns an effective address and TCP port. When a second Node server calls listen with the same address and port, the operating system rejects its bind request and Node emits EADDRINUSE. The correct resolution depends on whether the first owner is stale, legitimate, or the same application starting twice.Server A is listeningnode PID 48291:: or 0.0.0.0 : 3000Kernel bind tableTCP address + portowner recordedServer B startsserver.listen(3000)same effective bindBind rejectedEADDRINUSEaddress already in use:::3000Diagnose the existing owner before changing anythingStale ownerverify PID → graceful shutdownLegitimate other servicechoose a documented host portSame app starts twicefix duplicate bootstrap/listen
How Node.js EADDRINUSE occurs when two listeners request TCP port 3000

What :::3000 actually means

The three colons are not a typo. :: is the IPv6 unspecified address, analogous to IPv4 0.0.0.0. :::3000 means “IPv6 all interfaces, TCP port 3000.”

With Node's default ipv6Only: false, binding :: can provide dual-stack behavior: the same listener may accept IPv4 and IPv6 connections. The exact interaction depends on the operating system. That is why a process displayed as *:3000, 0.0.0.0:3000, or :::3000 can block what looks like a different address family.

Do not “fix” this by randomly forcing IPv4 or IPv6. Bind 127.0.0.1 for a local-only development service, 0.0.0.0 when a container or LAN-reachable development service needs IPv4, or an explicit ::/ipv6Only policy where IPv6 is intentional. The host address is part of the deployment contract.

Node version details and the TIME_WAIT myth

The ipv6Only listen option was added in Node.js 11.4.0. Current Node documentation lists reusePort support from Node 22.12.0 and 23.1.0, and only on operating systems that implement it. Check node --version before copying a deployment setting from a newer runtime into an older service.

Do not treat TIME_WAIT, SO_REUSEADDR, or reusePort as a universal fix for this error. A TIME_WAIT connection is not a LISTEN socket that can serve requests. Node already sets SO_REUSEADDR on its sockets, and reusePort deliberately distributes traffic only where the OS supports it. For EADDRINUSE on TCP 3000, inspect the active listener and the process lifecycle first.

Step-by-Step Solution

Step 1: Confirm that the failure is a listener collision

Capture the full error and the exact address. Do not assume that every EADDRINUSE involving 3000 belongs to the application you just ran.

Error: listen EADDRINUSE: address already in use :::3000
    at Server.setupListenHandle [as _listen2] (node:net:...)

Then inspect listening TCP sockets. Filtering to listeners avoids mistaking an outgoing connection for a server that owns the port.

Step 2: Identify and verify the owning process

macOS and Linux

Run this in the host environment where the failing Node command runs:

lsof -nP -iTCP:3000 -sTCP:LISTEN
 
# Example output:
# COMMAND   PID   USER   FD   TYPE             DEVICE SIZE/OFF NODE NAME
# node    48291  alex   21u  IPv6 0x1234567890      0t0  TCP *:3000 (LISTEN)
 
ps -p 48291 -o pid=,ppid=,user=,command=

lsof shows the owner; ps gives you a second check before ending it. On Linux, this alternative can expose the program and PID when permissions allow:

ss -ltnp 'sport = :3000'

If the command line identifies a stale local development server, request normal termination first:

kill -TERM 48291
lsof -nP -iTCP:3000 -sTCP:LISTEN

The second command should return no listener. Use kill -KILL 48291 only after you have confirmed the PID and the process fails to exit. A forceful signal skips cleanup code, which can lose logs, leave files half-written, and hide a shutdown bug you will meet again in production.

Windows PowerShell

PowerShell exposes the owning PID directly:

Get-NetTCPConnection -LocalPort 3000 -State Listen |
  Select-Object LocalAddress, LocalPort, OwningProcess
 
Get-Process -Id 48291
Stop-Process -Id 48291
 
Get-NetTCPConnection -LocalPort 3000 -State Listen

Replace 48291 with the OwningProcess value you inspected. The final command should produce no output. Stop-Process requests termination; reserve Stop-Process -Force for a verified process that refuses to stop.

On older Windows environments, Command Prompt provides the equivalent:

netstat -ano | findstr :3000
tasklist /FI "PID eq 48291"
taskkill /PID 48291

netstat may display IPv4 and IPv6 rows. Use the LISTENING entry and check the PID with tasklist before taskkill.

Step 3: Choose the correct fix, not the quickest-looking command

Decision tree for fixing Node.js EADDRINUSE safelyStart by finding a listener for the exact TCP port. If a verified listener exists, decide whether it is stale or legitimate. If no listener is visible, inspect duplicate application startup and container or WSL boundary layers. Use a dynamic port for parallel tests and platform configuration for cloud deployments.EADDRINUSE: address already in useDoes the exact port havea visible TCP listener?noInspect your startup pathduplicate listen, Docker, WSLThen check environmentCI worker, host mapping, PORTyesIs the verified ownerstale and safe to stop?yesGraceful terminationverify port is releasednoKeep owner runninguse deliberate alternate portParallel tests?listen on port 0read address().portclose after each test
Decision tree for fixing Node.js EADDRINUSE safely

Use the evidence from the previous step:

  1. A stale local process owns the port. Stop that verified process, then start the intended app once.
  2. A legitimate different service owns it. Assign your app a documented alternate port, such as 3001, rather than disrupting that service.
  3. Your app owns it twice. Fix the bootstrap code. Port changes only defer the failure to the next port.
  4. Docker, WSL, CI, or a platform owns it. Fix the host mapping or allocation at that layer. Killing a process inside a container cannot free a host port held by a different container.

Step 4: Change the port deliberately when two services should coexist

For a simple Node HTTP service, validate an environment-provided port and keep the default local:

const http = require("node:http")
 
function getPort(value) {
  const port = Number.parseInt(value ?? "3000", 10)
 
  if (!Number.isInteger(port) || port < 1 || port > 65535) {
    throw new Error("PORT must be an integer between 1 and 65535")
  }
 
  return port
}
 
const port = getPort(process.env.PORT)
const host = process.env.HOST ?? "127.0.0.1"
 
const server = http.createServer((request, response) => {
  response.writeHead(200, { "content-type": "text/plain; charset=utf-8" })
  response.end("healthy\n")
})
 
server.listen({ host, port }, () => {
  console.log("Listening on http://" + host + ":" + port)
})

Run a second local copy on a different port:

PORT=3001 node server.js
 
# Expected output:
# Listening on http://127.0.0.1:3001

In PowerShell, set the environment variable for the current session:

$env:PORT = "3001"
node server.js

The explicit 127.0.0.1 binding keeps this sample local. A container usually needs HOST=0.0.0.0 so the Docker network can reach Node inside the container. Do not bind broadly just because it is a familiar incantation; it changes who can reach the service.

Fix a Duplicate listen() Call in Your Application

The following pattern creates two HTTP servers that both request port 3000:

const express = require("express")
const http = require("node:http")
 
const app = express()
const port = 3000
 
app.get("/", (request, response) => {
  response.send("hello")
})
 
app.listen(port)
http.createServer(app).listen(port)

app.listen() already creates and starts an HTTP server. The second call therefore fails. Keep one listener. If you need the Server object for WebSockets or graceful shutdown, create it yourself and listen once:

const express = require("express")
const http = require("node:http")
 
const app = express()
const port = 3000
 
app.get("/", (request, response) => {
  response.send("hello")
})
 
const server = http.createServer(app)
 
server.listen(port, "127.0.0.1", () => {
  console.log("Listening on http://127.0.0.1:3000")
})

Search every startup path, not just the main file:

rg -n "(\.listen\(|createServer\()" src app server test

Common real-world sources are an imported module that starts itself as a side effect, a test helper also imported by production code, an if (require.main === module) guard missing from a CLI entry point, and a reload hook that calls bootstrap twice. A module that exports createApp() or createServer() is easier to test than one that binds during import.

For related configuration failures, see the guide to fixing a missing dotenv module and the React 19 upgrade notes, which are useful when a frontend and backend share a local environment.

Minimal Reproduction and a Test-Safe Fix

This complete script proves the kernel behavior without relying on Express, Next.js, or a shell process. The first server asks the OS for an available ephemeral port, then the second server tries to claim the same address and port.

const http = require("node:http")
 
function listen(server, options) {
  return new Promise((resolve, reject) => {
    const onError = (error) => reject(error)
 
    server.once("error", onError)
    server.listen(options, () => {
      server.off("error", onError)
      resolve()
    })
  })
}
 
function close(server) {
  return new Promise((resolve, reject) => {
    server.close((error) => (error ? reject(error) : resolve()))
  })
}
 
async function main() {
  const first = http.createServer()
  await listen(first, { host: "127.0.0.1", port: 0 })
 
  const address = first.address()
  const port = address.port
  const second = http.createServer()
 
  try {
    await listen(second, { host: "127.0.0.1", port })
  } catch (error) {
    console.log(error.code)
    console.log(error.address + ":" + error.port)
  } finally {
    await close(first)
  }
}
 
main().catch((error) => {
  console.error(error)
  process.exitCode = 1
})
 
// Expected output:
// EADDRINUSE
// 127.0.0.1:<an OS-assigned port>

port: 0 does not mean “listen on port zero.” It asks the OS to assign an available ephemeral port. Read the real port only after the listening callback or listening event. This is the right default for unit and integration tests that run in parallel.

Bad test pattern

const server = app.listen(3000)

Correct test pattern

const server = app.listen(0, "127.0.0.1")
 
server.on("listening", () => {
  const port = server.address().port
  console.log("Test server port:", port)
})

Close the returned server in your test framework's afterEach, afterAll, or finally block. A dynamically assigned port avoids collisions, while cleanup prevents hanging test runners and leaked handles.

Next.js, npm Scripts, and Development Servers

Next.js development defaults to port 3000. When another application should stay on 3000, pass a deliberate alternative:

npm run dev -- --port 3001
 
# Expected output includes a Local URL with port 3001.

For a standalone Next.js command, the equivalent is next dev -p 3001. Keep this choice in a team script or documented local environment rather than asking each developer to remember an untracked command.

Do not run next dev and a custom Node server that both listen on 3000 unless they are meant to be separate services with different ports. A Next.js custom server also needs one owner of startup. The same rule applies to Vite, CRA, nodemon, tsx watch mode, and IDE launch configurations: a watcher should restart one child process, not accumulate children.

If a port conflict appears only after a hot reload, log the PID at startup:

console.log("Starting server process", process.pid)

Two different PIDs suggest two processes or a watcher issue. The same PID with multiple bootstrap logs points to duplicate startup within one process. This small distinction saves a surprising amount of time.

For frontend request failures after the server does start, use this guide to debouncing React requests and the HTTP 429 troubleshooting guide. They address client traffic behavior; neither is a cure for a port bind failure.

Docker, Compose, and WSL

Docker: distinguish the host port from the container port

This Compose configuration runs Node on port 3000 inside the container and publishes it as port 3000 on the host:

services:
  web:
    build: .
    environment:
      HOST: 0.0.0.0
      PORT: "3000"
    ports:
      - "3000:3000"

The left side is the host port; the right side is the container port. If another container or local process owns host 3000, change only the host mapping:

services:
  web:
    build: .
    environment:
      HOST: 0.0.0.0
      PORT: "3000"
    ports:
      - "3001:3000"

Then visit http://localhost:3001. Inspect existing mappings before stopping a container:

docker ps --format "table {{.Names}}\t{{.Ports}}"
docker compose ps
docker compose port web 3000

The Docker CLI reports the host-to-container association. In the Compose sample, web is the service name; docker compose port resolves its generated container name for you. Stop only the container you have verified is obsolete. EXPOSE 3000 in a Dockerfile documents an intended container port; by itself it does not reserve or publish host port 3000. Docker's port-publishing documentation also warns that publishing without a loopback address can expose the port beyond the host. For a local-only service, prefer 127.0.0.1:3001:3000 where your Docker setup supports it.

WSL: inspect both sides of the boundary

WSL 2 runs Linux in a managed VM and integrates localhost with Windows. A port may be held by a Linux process, a Windows process, or a forwarded/proxied listener. Run the Linux lsof command inside WSL, then run the PowerShell Get-NetTCPConnection command on Windows. Do not assume the result from one environment describes the other.

If your app is intended to be reached from Windows, use an explicit host policy and test from the actual client. Avoid a blind 0.0.0.0 change: it may make the service reachable from network interfaces you did not mean to expose.

Production, Cloud, CI/CD, CPU, and GPU Notes

Production is not the place to kill whichever PID happens to own a port. A reverse proxy, load balancer, container orchestrator, or process manager may intentionally own the public socket. Your application normally binds a platform-provided PORT, while the platform handles routing and rollout.

Use one server object and close it on termination signals:

const http = require("node:http")
 
function getPort(value) {
  const port = Number.parseInt(value ?? "3000", 10)
 
  if (!Number.isInteger(port) || port < 1 || port > 65535) {
    throw new Error("PORT must be an integer between 1 and 65535")
  }
 
  return port
}
 
const port = getPort(process.env.PORT)
const host = process.env.HOST ?? "0.0.0.0"
 
const server = http.createServer((request, response) => {
  response.writeHead(200, { "content-type": "text/plain; charset=utf-8" })
  response.end("ok\n")
})
 
server.once("error", (error) => {
  console.error("Server failed to listen:", error.code, error.message)
  process.exitCode = 1
})
 
server.listen({ host, port }, () => {
  console.log("Server listening on " + host + ":" + port)
})
 
let shuttingDown = false
 
function shutdown(signal) {
  if (shuttingDown) return
  shuttingDown = true
  console.log("Received " + signal + "; stopping new connections")
 
  server.close((error) => {
    if (error && error.code !== "ERR_SERVER_NOT_RUNNING") {
      console.error("Shutdown failed:", error)
      process.exitCode = 1
    }
  })
}
 
process.once("SIGTERM", () => shutdown("SIGTERM"))
process.once("SIGINT", () => shutdown("SIGINT"))

server.close() stops accepting new connections and gives existing work a chance to complete. Real services should also set an operational shutdown deadline and close database, queue, and WebSocket clients in the right order. Do not add unbounded automatic retries for EADDRINUSE in production: another release might own the port permanently, and a retry loop conceals a bad deployment.

For Node cluster workers, use Node's supported shared-server behavior or a platform load balancer. Do not independently launch unrelated workers and hope they can all bind the same port. reusePort exists only on supported platforms and is a deliberate traffic-distribution feature, not a generic workaround.

In CI, a static port works only when every job has network isolation. Parallel workers on one runner should use port 0, a per-job allocated port, or container network isolation. In cloud deployments, bind the assigned PORT and verify the health-check path. CPU architecture, GPU availability, and CUDA drivers do not change EADDRINUSE; it is a host networking ownership problem. See why PyTorch CUDA may be unavailable only when a separate GPU startup issue prevents your app from reaching the bind step.

Verification Steps

After applying a fix, verify all of the following:

  1. The port has one expected listener.

    lsof -nP -iTCP:3000 -sTCP:LISTEN

    The command should show the intended process, or no process before startup.

  2. The startup log reports the expected host and port. Do not infer success from the absence of a stack trace; wait for the listening callback.

  3. A local health request reaches the intended server.

    curl --fail --silent --show-error http://127.0.0.1:3000/

    Expected output for the example server:

    healthy
  4. A second startup behaves predictably. If it should coexist, it uses its configured alternate port. If it should replace the first instance, the process manager performs a graceful handoff rather than a collision.

  5. Tests and containers clean up. Run the test suite twice and bring the Compose stack up/down twice. A failure only on the second run usually signals leaked server handles or a lingering container.

Troubleshooting Matrix

ObservationMost likely causeCheckCorrect action
lsof shows your old node PIDStale dev serverCommand line and parent PIDTerminate it gracefully
lsof shows an IDE, proxy, or another appLegitimate port ownerProduct/process namePreserve it; choose a new app port
No host PID, but Docker failsDocker mapping conflictdocker ps and docker portStop verified container or remap host port
Same Node PID logs startup twiceDuplicate bootstrapSearch .listen(Refactor to one listener
CI fails only with parallel workersStatic test portWorker count and open handlesUse port 0 and cleanup
WSL works in Linux but fails from WindowsForwarding/bind policyInspect both OSesAdjust host and verify real client path
Cloud health check fails though local worksIgnored assigned port or hostRuntime PORT and docsBind the platform port and required interface
Changing ports never helpsMultiple startup paths or security toolPIDs/command lines each attemptFix ownership and process lifecycle

Prevention

Use this checklist in projects that run a Node server:

  • Centralize process startup in one module. Export app construction separately from server binding.
  • Read PORT and HOST from validated configuration. Document local defaults.
  • Print PID, host, port, and environment once at startup without logging secrets.
  • Bind 127.0.0.1 for local-only tools. Review any 0.0.0.0 or public Docker publication as a security decision.
  • Give each local checkout an intentional port, or use a script that assigns it.
  • Use port 0 for test servers and close every handle in test cleanup.
  • Stop dev processes with Ctrl+C so they receive SIGINT and can close cleanly.
  • In Docker Compose, name host and container ports in documentation and avoid publishing services that only need internal container networking.
  • In CI/CD, use isolated networks, per-job ports, or deployment-native handoff instead of shell commands that kill broad groups of processes.

For a broader debugging toolkit, these related guides are useful:

Official References

FAQs

How do I fix Error: listen EADDRINUSE: address already in use :::3000?

Find the process listening on TCP 3000, verify its command line, then stop it gracefully if it is stale. On macOS/Linux, use lsof -nP -iTCP:3000 -sTCP:LISTEN. On Windows PowerShell, use Get-NetTCPConnection -LocalPort 3000 -State Listen. If the port is free after inspection, search for duplicate app.listen or server.listen calls.

What does :::3000 mean in Node.js?

:::3000 means Node tried to bind port 3000 on IPv6's unspecified address ::, representing all IPv6 interfaces. Node's normal dual-stack behavior can also make this listener cover IPv4. It can therefore conflict with an IPv4 listener on the same host port.

Why does EADDRINUSE return after I kill a process?

The process may restart under nodemon, an IDE, Docker Compose, PM2, a service manager, or a CI worker. Alternatively, the owner may not be Node at all. Inspect the new PID and command line each time; persistent recurrence is a process-lifecycle or host-port mapping problem, not evidence that you need a more forceful kill command.

Is changing from port 3000 to 3001 always safe?

No. It is safe when two services are intentionally meant to coexist and their clients, proxies, Docker mappings, and environment configuration all use the new port. It is the wrong fix for one application that calls listen twice or a cloud service that must bind the platform-provided PORT.

Can Node.js listen on the same port in multiple workers?

Sometimes, but only through an intentional shared-server strategy. Node cluster can share a server handle, and modern Node supports reusePort on some platforms. Neither feature makes independently started services safe to place on one port. Use a reverse proxy, orchestrator, cluster setup, or distinct ports according to your architecture.

Why does my Docker app fail when Node runs on port 3000 inside the container?

The conflict is usually the host side of 3000:3000. Docker must reserve host port 3000 before the container starts. Another host process or container can already own it. Keep the application on container port 3000 and map a free host port, such as 3001:3000, or remove the public mapping if only other containers need access.

Key takeaways

  • EADDRINUSE means the OS rejected a bind because an address and port are already owned by a listener.
  • :::3000 is an IPv6 unspecified-address binding; it is often dual-stack and can conflict with IPv4 port 3000.
  • Inspect the PID and command first. Stop a stale process gracefully before using a forceful kill.
  • Fix duplicate app.listen or server.listen calls in code; changing the port only hides that bug.
  • Docker host ports, WSL forwarding, test workers, and CI jobs can collide even when each app appears isolated.
  • Use port 0 for parallel test servers and read back the assigned port after the listening event.

Frequently asked questions

How do I fix Error: listen EADDRINUSE: address already in use :::3000?

Find the process listening on TCP port 3000, confirm it is safe to stop, then terminate it gracefully or use a different intentional port. On macOS and Linux, run lsof -nP -iTCP:3000 -sTCP:LISTEN. On Windows PowerShell, run Get-NetTCPConnection -LocalPort 3000 -State Listen. If no other process owns it, search your code for a duplicate app.listen or server.listen call.

What does :::3000 mean in a Node.js EADDRINUSE error?

:::3000 means Node tried to bind TCP port 3000 on the IPv6 unspecified address ::, which represents all IPv6 interfaces. With Node's default ipv6Only setting of false, that binding may also accept IPv4 traffic through dual-stack behavior. It can therefore conflict with a process that appears to be using IPv4 port 3000.

Why does EADDRINUSE keep happening after I kill Node?

The listener may be a Docker port mapping, a second terminal, an IDE task, a process manager, WSL port forwarding, or your own application calling listen twice. Inspect the listener again after stopping it and examine its command line. Do not assume every process on port 3000 is Node or that force-killing one PID fixes the source of the repeat.

Should I use kill -9 or taskkill /F for EADDRINUSE?

No, not first. Confirm the owning PID and send a normal termination signal so the process can close connections and remove temporary state. Use a forceful kill only when the verified process ignores graceful termination. Never use broad commands that kill every Node process on a shared workstation or production host.

How do I avoid EADDRINUSE in Node.js tests?

Do not hard-code port 3000 in tests that can run in parallel. Listen on port 0 so the operating system assigns a free ephemeral port, wait for the listening event, read server.address().port, and close the server in an afterEach or finally block. This prevents worker and CI collisions.

Why does Docker say port 3000 is already allocated when Node is not running?

Docker publishes a container port onto a host port. Another container, local service, or Docker-proxy may already own host port 3000 even though no Node process runs inside the new container. Inspect docker ps, then stop the owning container or map a different host port, such as 3001:3000. EXPOSE alone does not publish a host port.


Related Posts