PythonMastery
reference 3 min read · lesson 40 of 60 in Errors

OSError: [Errno 98] Address already in use

1 · The lesson

read

What this error means

You tried to bind a server to a port that something else already holds. Only one process can listen on a given host and port at a time, so the second one is refused.

This error happens on the server (listening) side. On the client side, the matching error is ConnectionRefusedError. The difference: here something is already listening on the port, but with ConnectionRefusedError, nothing is listening.

When you see it

python
Traceback (most recent call last):
  File "server.py", line 9, in <module>
    app.run(port=8000)
OSError: [Errno 98] Address already in use

On Windows:

python
OSError: [WinError 10048] Only one usage of each socket address is normally permitted

Why it happens

  • A previous run is still going. The terminal was closed without stopping it, or it detached and kept running.
  • Something else owns the port. On macOS, port 5000 is used by AirPlay Receiver. Port 8080 is the default port of many tools.
  • A dead process left the socket in TIME_WAIT. The OS holds the address for up to a couple of minutes after a close so that late packets from the old connection are not delivered to a new one.
  • Two workers in one config both binding the same port, rather than the parent binding once and sharing it.

How to fix it

Find out what holds it:

bash
lsof -iTCP:8000 -sTCP:LISTEN        # macOS and Linux: shows the PID and the command
ss -ltnp | grep 8000                # Linux
netstat -ano | findstr :8000        # Windows: the last column is the PID

Then stop that process, or use another port. Read the command name before you kill anything: on macOS, port 5000 is usually AirPlay, not a server you forgot to stop.

For TIME_WAIT during development, allow reuse. This lets a restart bind immediately instead of waiting for the timer:

python
import socket

s = socket.socket()
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)   # before bind, not after
s.bind(("0.0.0.0", 8000))
s.listen()

Most frameworks already do this. Flask's development server and uvicorn set it for you. That is why you rarely see TIME_WAIT problems with them, but often see them with a socket you create yourself.

Take the port from configuration so a collision is a one-line change rather than an edit:

python
import os

port = int(os.environ.get("PORT", "8000"))
app.run(host="0.0.0.0", port=port)
+ setup added so this can run · defines app
# Lightweight mock for objects whose attributes/methods aren't critical
class _AutoMock:
    def __init__(self, name='mock'): self._name = name
    def __getattr__(self, k): return _AutoMock(self._name + '.' + k)
    def __call__(self, *a, **kw):
        print('-> ' + self._name + '() called')
        return _AutoMock(self._name + '()')
    def __repr__(self): return '<mock ' + self._name + '>'
    def __str__(self): return '<mock ' + self._name + '>'
    def __bool__(self): return True
    def __iter__(self): return iter([])
    def __len__(self): return 0
    def __getitem__(self, k): return _AutoMock(self._name + '[...]')
    def __setitem__(self, k, v): pass
    def __enter__(self): return self
    def __exit__(self, *a): return False
    async def __aenter__(self): return self
    async def __aexit__(self, *a): return False
    def __add__(self, o): return self
    def __radd__(self, o): return self
    def __sub__(self, o): return self
    def __mul__(self, o): return self
    def __rmul__(self, o): return self
    def __truediv__(self, o): return self
    def __eq__(self, o): return isinstance(o, _AutoMock)
    def __hash__(self): return hash(self._name)
    def __lt__(self, o): return True
    def __le__(self, o): return True
    def __gt__(self, o): return False
    def __ge__(self, o): return False
    def __mro_entries__(self, bases): return (object,)

app = _AutoMock('app')

Let the OS choose the port when any port will do. This is useful in tests, where a fixed port makes parallel runs collide:

python
s.bind(("127.0.0.1", 0))        # port 0 means "pick any free port"
port = s.getsockname()[1]       # ask which port you got
+ setup added so this can run · defines s
# Lightweight mock for objects whose attributes/methods aren't critical
class _AutoMock:
    def __init__(self, name='mock'): self._name = name
    def __getattr__(self, k): return _AutoMock(self._name + '.' + k)
    def __call__(self, *a, **kw):
        print('-> ' + self._name + '() called')
        return _AutoMock(self._name + '()')
    def __repr__(self): return '<mock ' + self._name + '>'
    def __str__(self): return '<mock ' + self._name + '>'
    def __bool__(self): return True
    def __iter__(self): return iter([])
    def __len__(self): return 0
    def __getitem__(self, k): return _AutoMock(self._name + '[...]')
    def __setitem__(self, k, v): pass
    def __enter__(self): return self
    def __exit__(self, *a): return False
    async def __aenter__(self): return self
    async def __aexit__(self, *a): return False
    def __add__(self, o): return self
    def __radd__(self, o): return self
    def __sub__(self, o): return self
    def __mul__(self, o): return self
    def __rmul__(self, o): return self
    def __truediv__(self, o): return self
    def __eq__(self, o): return isinstance(o, _AutoMock)
    def __hash__(self): return hash(self._name)
    def __lt__(self, o): return True
    def __le__(self, o): return True
    def __gt__(self, o): return False
    def __ge__(self, o): return False
    def __mro_entries__(self, bases): return (object,)

s = _AutoMock('s')

When you'd see this in real code

  • A dev server started in the background by an earlier command, still holding port 8000 an hour later.
  • Two test files that each start a server on the same fixed port. Each one passes alone, but they fail when run together.
  • A container restarting faster than the OS releases the socket, so the first attempt after a crash fails and the retry succeeds.
  • flask run on macOS, where port 5000 is taken by AirPlay and not by your code at all.
  • [ConnectionRefusedError: [Errno 111] Connection refused](../error-connection-refused/): the client-side error that matches this one.
  • [PermissionError: [Errno 13] Permission denied](../error-permissionerror/): binding a port below 1024 without admin rights.

See Also

Found this useful? Share it with a friend who’s learning Python.