socket.error Errno 48 Address already in use
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
socket.error: [Errno 48] Address already in use appears when a program tries to bind a listening socket to an address and port that the operating system considers occupied. On macOS this is a common form of the "address in use" bind failure, and it usually points to either another live process or a recently closed socket that has not fully aged out yet.
Why the Bind Fails
A TCP server usually does something like this:
- create a socket
- bind it to an address and port
- listen for connections
Only one listener can normally own the same address and port combination at a time. If another process is already bound there, the second bind fails.
A quick Python example that can trigger the problem:
Run that script twice and the second process will usually fail with the address-in-use error.
Common Causes
The simplest cause is that another program is already using the port. That other program might be:
- a previous copy of your server
- a development framework that restarted badly
- an unrelated service such as AirPlay, Apache, or another local tool
Another common cause is a recently closed socket in the TIME_WAIT state. After a TCP connection closes, the operating system may keep the local endpoint reserved for a short time to avoid confusion with delayed packets from the old connection.
That is why quick restart loops often fail even when your application called close().
Finding the Process That Owns the Port
On macOS or Linux, lsof is the fastest first check:
If a process is listed, stop it or choose a different port. You can also inspect the process identifier directly:
That is usually better than guessing which service is responsible.
Using SO_REUSEADDR Correctly
When you control the server code, set SO_REUSEADDR before bind. This allows rebinding in cases where the port is stuck in a recently used state.
This does not let two active servers safely listen on exactly the same port in the usual case. It mainly helps with quick restarts after a previous socket has closed.
Frameworks often expose the same idea indirectly. For example, a dev server may offer a reload flag or configuration option that already enables port reuse.
Choosing a Different Port
Sometimes the right fix is simply not to fight for the same port. This is especially true in development when several services run locally.
For example:
If your application is configurable, read the port from an environment variable so you can avoid collisions cleanly:
Clean Shutdown Matters
If your server exits abruptly, sockets may linger and child processes may survive. A clean shutdown routine reduces that risk.
For long-running servers:
- close accepted client sockets
- close the listening socket
- stop background threads or subprocesses
- handle termination signals when appropriate
In Python, using with socket.socket(...) as server: can help ensure cleanup in small scripts.
Common Pitfalls
The first mistake is adding SO_REUSEADDR and assuming the problem is solved forever. If another live process is still bound to the port, reuse flags will not fix that.
Another common issue is forgetting that hot-reload tools may spawn child processes. You stop one process, but the reloader keeps the port open.
Developers also confuse client-side connections with listening sockets. The error occurs during bind, which is about becoming the server on that port, not about connecting outward to a remote host.
Finally, be careful when binding to 0.0.0.0. That reserves the port on all network interfaces, so a service listening on all interfaces conflicts with one listening on just 127.0.0.1 for the same port.
Summary
- '
Errno 48means the operating system will not let your process bind that address and port.' - The usual causes are another live process or a recently closed socket.
- '
lsof -i :portis the fastest way to find the current owner.' - '
SO_REUSEADDRhelps with restart timing but does not override an active listener.' - Clean shutdown and configurable ports make this error much easier to manage.
Related reading
- SocketException address incompatible with requested protocol
- Socket.IO with RabbitMQ?
- socket.shutdown vs socket.close
- Some clarification needed about synchronous versus asynchronous asio operations
- Softmax neural net works with error in implementation, does not work with correct implementation
- Solution to INSTALL_FAILED_INSUFFICIENT_STORAGE error on Android
- Spark-Streaming Kafka Direct Streaming API & Parallelism
- spark streaming + kafka - spark session API

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.