OSError: [Errno 113] No route to host in Python (tested)
OSError: [Errno 113] No route to host (EHOSTUNREACH) means the kernel could not reach the host at all. We reproduced both common causes: an address nobody answers (fails after about 3 seconds) and a firewall REJECT rule on a server that is up (fails instantly). It is a plain OSError, not a ConnectionError.
1. Reproduce it: connect to an address nobody answers
import socket, time
ip = socket.gethostbyname(socket.gethostname()) # this container's address
target = ip.rsplit(".", 1)[0] + ".250" # an unused address on the same subnet
t = time.monotonic()
try:
socket.create_connection((target, 80), timeout=10)
except OSError as e:
print(f"{type(e).__name__}: {e} (errno {e.errno}, after {time.monotonic() - t:.1f}s)")
Output:
OSError: [Errno 113] No route to host (errno 113, after 3.1s)
The container asked its subnet for .250 (an unused address). Nobody answered the ARP request, so after about 3 seconds the kernel gave up with EHOSTUNREACH. The same code on Alpine (musl libc) prints different text for the same errno:
OSError: [Errno 113] Host is unreachable (errno 113, after 3.1s)
So [Errno 113] No route to host and [Errno 113] Host is unreachable are the same error.
2. The surprising cause: a firewall REJECT rule
import socket, subprocess, time
# firewall on the server side: REJECT with icmp-host-prohibited (firewalld's default reject)
subprocess.run(["iptables", "-A", "INPUT", "-p", "tcp", "--dport", "8080",
"-j", "REJECT", "--reject-with", "icmp-host-prohibited"], check=True)
srv = socket.create_server(("0.0.0.0", 8080)) # the service IS listening
ip = socket.gethostbyname(socket.gethostname())
t = time.monotonic()
try:
socket.create_connection((ip, 8080), timeout=10)
except OSError as e:
print(f"{type(e).__name__}: {e} (after {time.monotonic() - t:.2f}s, server is up and listening)")
Output:
OSError: [Errno 113] No route to host (after 0.00s, server is up and listening)
The server was up and listening, yet the client got No route to host instantly. A firewall rule that rejects with icmp-host-prohibited (firewalld's default reject) produces exactly this errno. If the host answers ping but a port gives errno 113, check the server's firewall (firewall-cmd --list-all, iptables -L -n) and open the port, rather than debugging routing.
3. It is a plain OSError, not ConnectionError
import errno, socket
target = socket.gethostbyname(socket.gethostname()).rsplit(".", 1)[0] + ".250"
try:
socket.create_connection((target, 80), timeout=10)
except OSError as e:
print("errno name:", errno.errorcode[e.errno], "| EHOSTUNREACH =", errno.EHOSTUNREACH)
print("ConnectionError?", isinstance(e, ConnectionError), "| TimeoutError?", isinstance(e, TimeoutError))
print("class:", type(e).__name__)
Output:
errno name: EHOSTUNREACH | EHOSTUNREACH = 113
ConnectionError? False | TimeoutError? False
class: OSError
Python maps errno 111 to ConnectionRefusedError, but errno 113 has no subclass: except ConnectionError and except TimeoutError both miss it. Catch OSError and compare e.errno == errno.EHOSTUNREACH.
4. The same error through requests
import socket, requests
target = socket.gethostbyname(socket.gethostname()).rsplit(".", 1)[0] + ".250"
try:
requests.get(f"http://{target}/", timeout=10)
except requests.exceptions.ConnectionError as e:
print(type(e).__name__ + ":", e)
Output:
ConnectionError: HTTPConnectionPool(host='172.17.0.250', port=80): Max retries exceeded with url: / (Caused by NewConnectionError("HTTPConnection(host='172.17.0.250', port=80): Failed to establish a new connection: [Errno 113] No route to host"))
requests wraps it in requests.exceptions.ConnectionError with Max retries exceeded; the [Errno 113] at the end is the real cause.
5. Checklist
- Right address? A typo, a stale DNS record, or a DHCP address that changed points at an empty slot, which looks exactly like block 1.
- Host up? A machine that is off or asleep on the local network gives errno 113 after a few seconds (no ARP reply).
- Firewall? An instant errno 113 with the host up means a REJECT rule (block 2). Open the port on the server.
- Docker/VM networks? Container IPs (172.17.x.x) are only reachable from the same host or network; from elsewhere publish a port (
-p 8080:8080) and connect to the host's address.
Related: [Errno 101] Network is unreachable · [Errno 111] Connection refused · socket errors and errno codes.
Frequently asked questions
What does [Errno 113] No route to host mean?
EHOSTUNREACH: the host did not answer at the network level (wrong IP, host down) or a firewall rejected the connection with an ICMP host-prohibited reply.
Why do I get No route to host when the server is running?
A firewall REJECT rule (firewalld rejects with icmp-host-prohibited by default) returns errno 113 instantly. Open the port in the server's firewall.
How do I catch Errno 113 in Python?
except OSError as e: if e.errno == errno.EHOSTUNREACH. It is not a ConnectionError subclass, so except ConnectionError misses it.
Written with AI assistance. Measured on 2026-10-23 in Docker: python:3-slim (Python 3.15.1, glibc, requests from pip) and python:3-alpine (musl). The firewall test ran iptables inside its own container. Each block was run verbatim and the output pasted unedited. PlainHeaders is our extension; Python is free.