socket programming
Errno 48
address in use error
troubleshooting sockets
network programming errors

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.

Practice system design

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:

  1. create a socket
  2. bind it to an address and port
  3. 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:

python
1import socket
2
3server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
4server.bind(("127.0.0.1", 8000))
5server.listen()
6
7print("listening on 127.0.0.1:8000")
8input("press enter to exit")
9server.close()

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:

bash
lsof -i :8000

If a process is listed, stop it or choose a different port. You can also inspect the process identifier directly:

bash
ps -p 12345 -o pid,command

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.

python
1import socket
2
3server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
4server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
5server.bind(("127.0.0.1", 8000))
6server.listen()
7
8print("listening on 127.0.0.1:8000")
9
10while True:
11    client, address = server.accept()
12    client.sendall(b"hello\\n")
13    client.close()

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:

python
PORT = 8081
server.bind(("127.0.0.1", PORT))

If your application is configurable, read the port from an environment variable so you can avoid collisions cleanly:

python
1import os
2import socket
3
4port = int(os.environ.get("PORT", "8000"))
5server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
6server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
7server.bind(("127.0.0.1", port))
8server.listen()
9print(f"listening on {port}")

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 48 means 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 :port is the fastest way to find the current owner.'
  • 'SO_REUSEADDR helps with restart timing but does not override an active listener.'
  • Clean shutdown and configurable ports make this error much easier to manage.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track 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.

Practice system design

All Rights Reserved.