Of course. Understanding socket.error and its relationship with the errno module is fundamental to writing robust network programs in Python. This error is the primary way your program is notified of low-level, system-level network issues.

Here's a comprehensive breakdown.
The Core Concept: socket.error
In Python, almost all socket-related errors are raised as exceptions of the type socket.error. This is a base class for all socket exceptions.
- Location: It's in the
socketmodule, so you import it asimport socket. - Inheritance:
socket.errorinherits fromOSError. This means you can catch it with atry...except OSError as e:block, which is a common and recommended practice.
# This is the most common way to catch socket errors
try:
# Some socket operation that might fail
s.connect(('some-non-existent-server.com', 80))
except OSError as e:
print(f"A system/OSError occurred: {e}")
The Role of errno: The Error Number
When a socket.error (or OSError) is raised, it contains two key pieces of information:
- The error message: A human-readable string (e.g., "Connection refused").
- The error number (errno): An integer that uniquely identifies the specific error. This number is a standard defined by the operating system (POSIX).
The errno module in Python provides a human-readable name for these common error numbers.

- Location: It's a built-in module, so you import it as
import errno.
How to Access errno from an Exception
The exception object has an attribute .errno that holds this integer.
import socket
import errno
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(('127.0.0.1', 65432)) # Try to connect to a port that is likely not listening
except OSError as e:
print(f"Error message: {e}")
print(f"Error number (errno): {e.errno}")
# Now use the errno module to get the name of the error
if e.errno == errno.ECONNREFUSED:
print("The connection was refused. The server is probably not running.")
elif e.errno == errno.ETIMEDOUT:
print("The connection timed out.")
else:
print(f"An unknown error occurred with errno: {e.errno}")
Common errno Values and Their Meanings
Here is a table of the most frequent socket errors you'll encounter, along with their errno number and name.
Error Name (errno) |
Number | Description | Common Scenario |
|---|---|---|---|
ECONNREFUSED |
111 | Connection refused. | You tried to connect to a port, but there is no process (server) listening on that port. |
ETIMEDOUT |
110 | Connection timed out. | The server didn't respond within a certain period (the timeout you set on the socket). |
EHOSTUNREACH |
113 | No route to host. | The network cannot deliver the data to the specified IP address. The host might be down or fireblocked. |
EADDRINUSE |
98 | Address already in use. | You tried to bind() a socket to an IP/port that is already in use by another socket on your machine. |
EAFNOSUPPORT |
97 | Address family not supported. | You tried to use an address family (e.g., AF_INET6) that your system or socket type doesn't support. |
ENETUNREACH |
101 | Network is unreachable. | Similar to EHOSTUNREACH, but the network itself is not reachable from your machine. |
ECONNRESET |
104 | Connection reset by peer. | The other side closed the connection forcefully. This often happens with HTTP keep-alive when a server times out a connection. |
EBADF |
9 | Bad file descriptor. | You tried to use a socket that has already been closed. |
Practical Examples
Let's see these errors in action.
Example 1: ECONNREFUSED (Connection Refused)
This happens when you try to connect to a port with no listener.

import socket
import errno
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# Port 12345 is unlikely to have a server running
try:
s.connect(('127.0.0.1', 12345))
except OSError as e:
print(f"Caught an error: {e}")
print(f"Error number: {e.errno}")
if e.errno == errno.ECONNREFUSED:
print("Success! We correctly identified 'Connection refused'.")
finally:
s.close()
Output:
Caught an error: [Errno 111] Connection refused
Error number: 111
Success! We correctly identified 'Connection refused'.
Example 2: EADDRINUSE (Address Already in Use)
This happens when you try to start a server on a port that is already in use.
import socket
import errno
# Start a server on port 8080
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.bind(('127.0.0.1', 8080))
server_socket.listen(1)
print("Server is listening on port 8080. Press Ctrl+C to stop.")
# Now, try to start another server on the *same* port
try:
second_server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
second_server.bind(('127.0.0.1', 8080)) # This will fail
except OSError as e:
print(f"\nCaught an error in the second server: {e}")
print(f"Error number: {e.errno}")
if e.errno == errno.EADDRINUSE:
print("Success! We correctly identified 'Address already in use'.")
finally:
server_socket.close()
Output:
Server is listening on port 8080. Press Ctrl+C to stop.
Caught an error in the second server: [Errno 98] Address already in use
Error number: 98
Success! We correctly identified 'Address already in use'.
Best Practices
-
Always Catch
OSError(orsocket.error): When performing socket operations, wrap them in atry...except OSErrorblock. This is the Pythonic way to handle system-level errors. -
Use
.errnofor Programmatic Logic: Don't just print the error string. Use thee.errnoattribute to check for specific conditions and implement retry logic, fallbacks, or user-friendly messages. -
Set Timeouts: To avoid your program hanging indefinitely, always set a timeout on your sockets using
s.settimeout(seconds). This will cause operations likeconnect()andrecv()to raise anOSErrorwitherrno.ETIMEDOUTif they take too long. -
Clean Up Resources: Use a
finallyblock to ensure your sockets are always closed, even if an error occurs.
import socket
import errno
import time
def connect_with_retry(host, port, max_retries=3, timeout=5):
retries = 0
while retries < max_retries:
s = None
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.settimeout(timeout)
print(f"Attempt {retries + 1}: Connecting to {host}:{port}...")
s.connect((host, port))
print("Connection successful!")
return s # Return the connected socket
except OSError as e:
print(f"Error: {e}")
if e.errno == errno.ECONNREFUSED:
print("Connection refused. Retrying in 2 seconds...")
elif e.errno == errno.ETIMEDOUT:
print("Connection timed out. Retrying in 2 seconds...")
else:
print(f"An unexpected error occurred: {e.errno}. Not retrying.")
break # Don't retry on unknown errors
retries += 1
time.sleep(2)
finally:
if s: # If socket was created but connection failed, close it
s.close()
print("Failed to connect after multiple retries.")
return None
# This will likely fail and demonstrate the retry logic
connect_with_retry('127.0.0.1', 12345)
Summary
| Concept | What it is | Why it's important |
|---|---|---|
socket.error |
The exception class raised for socket problems. | It's the entry point for all error handling in socket programming. |
errno |
An integer code that identifies the specific error. | It allows your program to distinguish between "connection refused" and "timed out" and react accordingly. |
errno module |
A Python module that maps error numbers to readable names (e.g., errno.ECONNREFUSED). |
It makes your code more readable and maintainable than using magic numbers like 111. |
