Node Inspector Port In Use — Debugger Cannot Attach
Resolve "address already in use" and debugger attach failures by finding the process holding port 9229 and selecting a different inspector port.
Symptoms
- Node prints "Starting inspector on 127.0.0.1:9229 failed: address already in use"
- The IDE debugger connects to the wrong process or not at all
- A previous run that crashed still holds the debug port
Possible causes
- A stale Node process from an earlier debug session still listens on 9229
- Another tool or IDE already binds the same inspector port
- node --inspect is started while a --inspect-brk session is already running
Diagnosis steps
Find the process holding the port
lsof -i :9229 || ss -ltnp | grep 9229Interpretation
The PID and command tell you whether it is a stale Node run or an unrelated tool.
Start the inspector on a free port
node --inspect=127.0.0.1:9230 app.jsInterpretation
Any unused port works; update the IDE attach target to match.
Confirm the inspector endpoint responds
curl http://127.0.0.1:9230/json/listInterpretation
A JSON list with a webSocketDebuggerUrl means the inspector is reachable and attach will succeed.
Root cause
Node inspector binds a TCP port (9229 by default). Only one process can bind a given address and port, so when a stale debug session still holds it the new inspector start fails and the debugger cannot attach.
Fix
Kill the stale process or choose a distinct port with --inspect-port/--inspect, and add a script that selects an available port to avoid collisions in scripts and CI.
Risk note
An inspector bound to 0.0.0.0 exposes a debugger to the network; always bind 127.0.0.1 outside local development.
Verify the fix
Start the app with the new port, open the inspector URL, and confirm the process appears in the target list; set a breakpoint to prove attach works.
Symptoms
This debugging guide addresses “Node Inspector Port In Use — Debugger Cannot Attach”. Start from the symptoms, follow the ordered diagnostics, and confirm each hypothesis before moving on; the fix and verification steps then close the loop.
Observed symptoms include:
- Node prints “Starting inspector on 127.0.0.1:9229 failed: address already in use”
- The IDE debugger connects to the wrong process or not at all
- A previous run that crashed still holds the debug port
Reproduce and Diagnose
Reproduce the failure in isolation before changing any code. Work through the checks below in order; each one narrows the search space.
Step 1: Find the process holding the port
lsof -i :9229 || ss -ltnp | grep 9229
The PID and command tell you whether it is a stale Node run or an unrelated tool.
Step 2: Start the inspector on a free port
node --inspect=127.0.0.1:9230 app.js
Any unused port works; update the IDE attach target to match.
Step 3: Confirm the inspector endpoint responds
curl http://127.0.0.1:9230/json/list
A JSON list with a webSocketDebuggerUrl means the inspector is reachable and attach will succeed.
Likely contributors, in order of frequency:
- A stale Node process from an earlier debug session still listens on 9229
- Another tool or IDE already binds the same inspector port
- node –inspect is started while a –inspect-brk session is already running
Root Cause
Node inspector binds a TCP port (9229 by default). Only one process can bind a given address and port, so when a stale debug session still holds it the new inspector start fails and the debugger cannot attach.
The Fix
Kill the stale process or choose a distinct port with –inspect-port/–inspect, and add a script that selects an available port to avoid collisions in scripts and CI.
Watch out: An inspector bound to 0.0.0.0 exposes a debugger to the network; always bind 127.0.0.1 outside local development.
# find and stop the stale debug session
lsof -ti :9229 | xargs -r kill
# start on an explicit free port
node --inspect=127.0.0.1:9230 --inspect-brk ./server.js
# verify the target is listed
curl -s http://127.0.0.1:9230/json/list | head
Verify and Prevent
Start the app with the new port, open the inspector URL, and confirm the process appears in the target list; set a breakpoint to prove attach works.
Once verified, add a regression test that reproduces the original symptom so the failure cannot silently return.
This class of failure is usually environmental rather than pure logic, so capture the exact command, the environment variables, and the working directory in your bug report. Reproduce it in the smallest possible script, then widen the scope only once the minimal case is understood. A short written checklist for this failure mode saves hours the next time it appears.