OSError: [Errno 98] Address already in use

Python · updated 2026-11-03

Raised when a server binds a host and port that something already holds: socket.bind(), uvicorn, gunicorn, Flask and Django runserver all hit it at startup. On macOS the number is [Errno 48].

Traceback (most recent call last):
  File "/app/server.py", line 40, in <module>
    app.run(host="0.0.0.0", port=5000)
  ...
  File "/usr/lib/python3.12/socketserver.py", line 473, in server_bind
    self.socket.bind(self.server_address)
OSError: [Errno 98] Address already in use

Quick fix

Find what holds the port with lsof -nP -iTCP:<port> -sTCP:LISTEN (or ss -ltnp on Linux), stop it if it is an old copy of your app, or start on a different port. On macOS, port 5000 is often taken by AirPlay Receiver.

  1. Run lsof -nP -iTCP:5000 -sTCP:LISTEN (replace 5000 with your port) to see the PID.
  2. Check it with ps -p <PID> -o command, then stop it with kill <PID>.
  3. Read the port from an environment variable so you can change it without code edits.
  4. For your own socket servers, set SO_REUSEADDR before bind so restarts do not wait for TIME_WAIT.
  5. On macOS, turn off AirPlay Receiver if port 5000 or 7000 is busy.
python
import os, socket

port = int(os.environ.get("PORT", "8000"))
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)  # restart without waiting
sock.bind(("0.0.0.0", port))
sock.listen()

Why it happens

An old copy of the server is still running

A previous run left in the background, a crashed debugger session, or a dev server reloader that spawned a child keeps the port.

Another service uses the same port

Two apps configured for 8000, a Docker container publishing the port, or macOS AirPlay Receiver on 5000 and 7000.

Restarting a socket server too quickly

Without SO_REUSEADDR, a port can stay unavailable for a short time after the previous process exits (TIME_WAIT).

Two workers binding the same port

Starting the app twice in one deploy, or a process manager and a manual run both binding the port, makes the second one fail.

Other fixes

  • With gunicorn, let it own the socket and run multiple workers instead of starting several processes yourself.
  • In tests, bind to port 0 and read the assigned port so test runs never collide.

Same error, other wording

  • OSError: [Errno 48] Address already in use
  • ERROR: [Errno 98] error while attempting to bind on address ('0.0.0.0', 8000): address already in use
  • [ERROR] Connection in use: ('0.0.0.0', 8000)

Let your coding agent catch the next one

Runheed records this error in production with the stack trace, the breadcrumbs before it and the agent session that shipped the code, and serves it to Claude Code, Cursor or any MCP client. With it connected, you can ask:

> Find the 'Address already in use' errors in production, show me which port and which process held it, and fix the restart or deploy step so only one copy binds the port.

Plans from $29/moSee what your agent readsSee the setupCancel any time from the billing portal

Related errors

References: Python docs: socket (SO_REUSEADDR, bind), Uvicorn docs: settings (host, port, fd)