Skip to content
Nilay Kabariya

Entry No.003·Fixes·Updated ·5 min read

Windows 11 address already in use: 3 traps beyond taskkill

Address already in use on Windows 11 (EADDRINUSE), but the PID is Docker, WSL or nothing at all. Reproduced: when not to kill it, and which port to pick.

by Nilay#node#windows#devserverFIXED

The error, verbatim

Jump to the fix ↓
node:events:486
      throw er; // Unhandled 'error' event
      ^
Error: listen EADDRINUSE: address already in use :::3000
    at Server.setupListenHandle [as _listen2] (node:net:1948:16)
    at listenInCluster (node:net:2005:12)
    at Server.listen (node:net:2110:7)
✓ Reproduced on Windows 11 Pro; Windows Server 2025 (GitHub Actions, November 2)

Tested on

Node
24.14.0
OS
Windows 11 Pro; Windows Server 2025 (GitHub Actions, November 2)
Python
3.14.5
Shells
PowerShell 5.1, cmd
kill-port
2.0.1
Docker Desktop
Engine 29.8.2 (WSL 2)
Reserved ports
re-checked November 7, 2026, after a restart (Node 24.14.0)

✓ Last re-run on GitHub Actions · see the run · all repros

Contents
  1. The fix01
  2. The same error from Python and other programs02
  3. Check what you’re about to stop03
  4. Or just use another port04
  5. One command instead of two05
  6. When netstat points at Docker or WSL06
  7. “Permission denied” instead: ports Windows reserves07
  8. No error, but the wrong app answers08
  9. Why it happens09
  10. What didn’t work10
  11. How this was tested11

The fix

Another process is already listening on the port. Find its process ID (PID), stop it, then start your server again.

PowerShell:

Get-NetTCPConnection -LocalPort 3000 -State Listen | Select-Object OwningProcess
Stop-Process -Id <PID> -Force

Command Prompt:

netstat -ano | findstr :3000
taskkill /PID <PID> /F

In netstat, the PID is the last number on the LISTENING line:

TCP    0.0.0.0:3000    0.0.0.0:0    LISTENING    11156

The same error from Python and other programs

Node calls it EADDRINUSE. Windows’ own wording, which Python passes straight through, is this (other languages word it their own way):

OSError: [WinError 10048] Only one usage of each socket address (protocol/network address/port) is normally permitted

Same meaning, same fix. The commands above don’t care what language the program is written in; they ask Windows which process owns the port. I checked that with a Python server holding port 5055:

Get-NetTCPConnection -LocalPort 5055 -State Listen reported owning process 12500, and Get-Process -Id 12500 named it python. netstat agreed:

  TCP    127.0.0.1:5055         0.0.0.0:0              LISTENING       12500

Stopping it freed the port immediately.

Check what you’re about to stop

The PID might be a dev server from another project that you still need. Look before you stop it:

Get-Process -Id <PID>

Or just use another port

Most dev servers accept a port flag or a PORT environment variable:

npx next dev -p 3001
npx vite --port 5174

For your own Node server, read the port from the environment so it’s easy to change:

const port = Number(process.env.PORT) || 3000;
server.listen(port);

One command instead of two

If you just want the port back and you’ve already checked what holds it:

npx kill-port 3000

It stops whatever owns the port without showing you what that is, so look first (the section above).

When netstat points at Docker or WSL

If the PID belongs to com.docker.backend.exe or wslrelay.exe, a Docker container (or a server inside WSL) has published that port to Windows. I ran a container with -p 3020:5432 and started a Node server on 3020:

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

  TCP    0.0.0.0:3020    0.0.0.0:0    LISTENING    19044   ← com.docker.backend.exe
  TCP    [::1]:3020      [::]:0       LISTENING    12540   ← wslrelay.exe

Don’t kill those PIDs: they’re Docker Desktop and WSL themselves, not your app.

Find the container that publishes the port, and stop that:

docker ps --filter "publish=3020"
docker stop <container-name>

“Permission denied” instead: ports Windows reserves

Sometimes the error on Windows 11 isn’t EADDRINUSE at all, and netstat shows nothing on the port:

Error: listen EACCES: permission denied 0.0.0.0:50100

Windows keeps blocks of ports reserved for itself, and features like Hyper-V, WSL and Docker can add more. Nothing is listening on those ports, so there’s no PID to stop. Python got through on a port that Node was refused on, so it depends on the program too. On my machine, port 80 and several ranges between 50060 and 53201 were reserved; 3000 wasn’t.

List the reserved ranges, then pick a port outside all of them:

netsh interface ipv4 show excludedportrange protocol=tcp

No error, but the wrong app answers

The opposite surprise: two programs on the same port, and no error at all. On Windows one app can listen on the IPv4 address 127.0.0.1:3000 while another listens on the IPv6 side (::, Node’s default), and both start fine. I ran a Python server on 127.0.0.1:3013 and a Node server on port 3013 at the same time:

$ curl http://localhost:3013/      →  node app on ::
$ curl http://127.0.0.1:3013/      →  python app on 127.0.0.1

localhost went to the Node app, so the browser showed one app while the other was still running unseen. netstat lists both, which is the clue:

TCP    0.0.0.0:3013     0.0.0.0:0    LISTENING    18512
TCP    127.0.0.1:3013   0.0.0.0:0    LISTENING    5564
TCP    [::]:3013        [::]:0       LISTENING    18512

Two different PIDs on one port means two programs. Stop the one you don’t want with the commands at the top, or give one of them another port.

It can go further than the IPv4/IPv6 split. On November 2, on a Windows Server 2025 machine (GitHub’s windows-latest runner), Node and Python shared the same port with no error at all. With a Node server holding 0.0.0.0:3001 and [::]:3001, a Python socket bound both addresses without complaint, and with Python holding a port, Node started on it and printed that it was listening. Two Python servers on the same port did conflict, with the WinError 10048 above. So on Windows, a missing EADDRINUSE doesn’t prove the port was free: check netstat -ano for a second PID.

Why it happens

Only one process can listen on a given port at a time. The usual culprits:

  • a dev server still running in another terminal tab or editor window
  • a server from a crashed or closed session that’s still running in the background
  • two projects that both default to port 3000
  • a Docker container publishing the same port

What didn’t work

How this was tested

November 2, 2026: re-run on GitHub Actions windows-latest (Windows Server 2025, Node 24.22.1, Python 3.12.10). A second Node server on a busy port failed with EADDRINUSE; Get-NetTCPConnection and netstat -ano both named the right PID; Stop-Process and taskkill /F freed the port; npx kill-port printed Process on port 3001 killed; Node got EACCES on port 80, inside the machine’s excluded range; and localhost reached the Node app on :: while 127.0.0.1 reached the Python one. Docker wasn’t re-run. The script and output are public.

— N.K., end of entry No.003

Useful? Pass it on:Post on XFollow @EmotionalMatter

Related entries

  1. No.016

    Fix: 'vite' is not recognized as an internal or external command

    Windows says the command doesn't exist, but it's right there in node_modules. Five causes, how to tell them apart in one command, and what each one needs.

    > 'vite' is not recognized as an internal or external command,

    FIXED5 minWindows
  2. No.093

    Fix: bigint Failed to load bindings, pure JS will be used

    bigint: Failed to load bindings, pure JS will be used. Why npm 12 shows it on every install, whether it matters, and how to get the native build back.

    > bigint: Failed to load bindings, pure JS will be used (try npm run rebuild?)

    FIXED3 minWindows
  3. No.072

    npm error code ENOENT, and spawn npx ENOENT on Windows

    Read the path line first. On Windows, spawn npx ENOENT has a twist: adding .cmd now fails with EINVAL. Four ENOENT causes reproduced, each with its fix.

    > npm error code ENOENT

    FIXED3 minWindows
  4. No.071

    Fix: JavaScript heap out of memory (Node.js, tested)

    FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory. Default limits measured, and two ways the usual fix silently fails.

    > FATAL ERROR: Reached heap limit Allocation failed - JavaScript heap out of memory

    FIXED2 minWindows

Post card · Every Sunday

What broke this week.

One email on Sundays: the Node, TypeScript, Python and AI SDK releases that broke builds that week, each one reproduced, with a link to the fix that worked. Never shared, and you can leave any time.

— Nilay

or follow by RSSor on X

By subscribing you agree to the privacy note. One click to leave.

tip: paste the exact error text