DEV Community

Tj Thouhid
Tj Thouhid

Posted on

Port already in use? How to fix it when your AI coding agent keeps starting servers

You ask your AI coding agent to run the app, and you get this:

Error: listen EADDRINUSE: address already in use :::3000
Enter fullscreen mode Exit fullscreen mode

Or worse, you don't get an error at all. The agent's server quietly starts on 3001, your browser is still on 3000, and you spend ten minutes wondering why your change isn't showing up.

I wrote a general guide to finding and stopping whatever is using port 3000 on a Mac. This post is about the version of the problem that AI agents cause, because it happens a lot more often now, and it's easy to prevent once you know why.

Why AI agents leave servers running

Claude Code, Cursor, Codex and similar tools all run shell commands for you. That's useful, but dev servers are a bad fit for how they work:

  • Background servers. A dev server never finishes, so agents often start it in the background, check that the page loads, and move on. Nothing tells them to stop it later.
  • Re-runs. Later in the same session, or in a new session, the agent wants to test again. It doesn't know a server is already running, so it starts another one. Many dev servers (Vite, for example) quietly move to the next free port, so you end up with copies on 3000, 3001 and 3002.
  • Crashed or closed sessions. If the agent's session crashes, or you close the window, the server it started can keep running with no parent. On macOS it gets adopted by launchd and just sits there.
  • Several agents at once. Two agents on one project both want the same port. The second one either fails or picks a random port.

So the fix has two parts: clean up what's running now, then stop it happening again.

Step 1: find what's listening on the port

lsof -nP -iTCP:3000 -sTCP:LISTEN
Enter fullscreen mode Exit fullscreen mode
  • -iTCP:3000 looks only at TCP on port 3000.
  • -sTCP:LISTEN shows only the process that's listening, which is the one holding the port. Without it you'd also see your browser's connections.
  • -n and -P skip name lookups, so it's faster and shows 3000 instead of a service name.

You'll get something like:

COMMAND   PID USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
node    48213 tj     23u  IPv6  0x...       0t0  TCP *:3000 (LISTEN)
Enter fullscreen mode Exit fullscreen mode

To see every listening port at once, which is handy after a long agent session:

lsof -nP -iTCP -sTCP:LISTEN
Enter fullscreen mode Exit fullscreen mode

Step 2: check what it is and who started it

Before you stop anything, find out what it is. Take the PID and ask ps:

ps -o pid,ppid,etime,command -p 48213
Enter fullscreen mode Exit fullscreen mode
  PID  PPID  ELAPSED COMMAND
48213     1 01:12:40 node /Users/you/code/shop/node_modules/.bin/vite
Enter fullscreen mode Exit fullscreen mode
  • command shows the full command line, which usually includes the project folder. That tells you which project it belongs to.
  • etime (shown as ELAPSED) is how long it's been running. An hour means it's not the server you just started.
  • ppid is the parent process. Run the same ps command on that PID to see what launched it. You'll often find a shell that belongs to your editor or AI tool. If the PPID is 1, the thing that started it has already gone, and this is a leftover.

If it's a database, Docker or something you didn't expect, stop and think before going further.

Step 3: stop it safely

Ask it to quit first:

kill 48213
Enter fullscreen mode Exit fullscreen mode

This sends SIGTERM, a polite "please quit", so the server can close files and connections properly. Wait a couple of seconds and run the lsof command from step 1 again.

Only if it's still there:

kill -9 48213
Enter fullscreen mode Exit fullscreen mode

kill -9 ends it straight away with no cleanup. Use it second, not first.

If you're sure the listener on 3000 is a leftover dev server and want one line, this stops only the process that's listening on that port:

kill $(lsof -t -iTCP:3000 -sTCP:LISTEN)
Enter fullscreen mode Exit fullscreen mode

The -sTCP:LISTEN part matters. Without it, lsof also returns other processes connected to the port, such as your browser, and you'd send them the signal too.

If the server comes straight back after you stop it, something is restarting it, such as Docker, a process manager or a tool like Laravel Herd. Stop it there instead.

Step 4: stop it happening again

Cleaning up is fine once. Doing it every day gets old. These changes made the biggest difference for me.

Give each agent a fixed port. Put it in the project's .env:

PORT=3001
Enter fullscreen mode Exit fullscreen mode

And make the dev server fail instead of drifting to a random port. For Vite:

npm run dev -- --port 3001 --strictPort
Enter fullscreen mode Exit fullscreen mode

A server that fails loudly on a busy port is much easier to deal with than one that silently moves to 3004.

If you run more than one agent on the same project, give each one its own folder (a git worktree) and its own port, so they never compete for 3000.

Write the rules down for the agent. Agents read CLAUDE.md (Claude Code) or AGENTS.md (Codex and others). Add a short section:

## Dev server
- Run it with: `npm run dev -- --port 3001 --strictPort`
- Use port 3001 only.
- Before starting a server, check if one is already running:
  `lsof -nP -iTCP:3001 -sTCP:LISTEN`. If it is, reuse it.
- Stop any server you started when the task is done.
Enter fullscreen mode Exit fullscreen mode

This one change cut my duplicate servers by more than anything else.

Stop servers when you're done. At the end of a session, ask the agent to stop what it started, or run lsof -nP -iTCP -sTCP:LISTEN yourself and clear out anything left over. It takes ten seconds and saves the confusing "why is my old code showing?" moment the next morning.

Doing this in Lokstack

Disclosure: I build Lokstack, a Mac app, and this part is about my own app.

I got tired of running these commands after every agent session, so Lokstack does the looking for you. Search for a port and it shows what's using it, which project it belongs to and who started it. Stop asks the program to quit, like kill. Force stops it straight away, like kill -9. The Agents screen has a Left running panel that lists the dev servers AI tools started and didn't stop. All of that is on the free plan.

Lokstack Ports screen showing who owns each port, with Stop and Force buttons

Lokstack Left running panel listing servers AI tools forgot to stop

Here's a short video of finding and freeing a busy port:

If you'd rather stay in Terminal, the commands above are all you need. https://lokstack.app

What's the most servers you've found an agent left running? Tell me in the comments.

Top comments (0)