OSError: [Errno 98] Address already in use
1 · The lesson
readWhat 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
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:
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:
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:
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:
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:
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 runon macOS, where port 5000 is taken by AirPlay and not by your code at all.
Related errors
- [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
- All Python errors: the full index, by type and by when it happens.
- Environment & Configuration
- DevOps & Deploy
Found this useful? Share it with a friend who’s learning Python.