OSError: [Errno 101] Network is unreachable in Python (tested fix)

OSError: [Errno 101] Network is unreachable means the OS has no route to the address you connected to, so it fails instantly. We reproduced it in a container with no network and tested how to catch it and retry.

1. What Errno 101 means

import socket
for host in ("1.1.1.1", "2606:4700::1111"):
    fam = socket.AF_INET6 if ":" in host else socket.AF_INET
    s = socket.socket(fam)
    try:
        s.connect((host, 80))
    except OSError as e:
        print(f"{type(e).__name__}: {e}")
    finally:
        s.close()

Output:

OSError: [Errno 101] Network unreachable
OSError: [Errno 101] Network unreachable

The kernel has no route for the destination address: no network interface is up, there is no default gateway, or (for IPv6) the host has no IPv6 connectivity at all. The connect fails at once instead of timing out. We reproduced it in a Docker container started with --network none (python:3.11-alpine). Alpine uses musl libc, which words it Network unreachable; on glibc systems (Debian, Ubuntu, most desktops) the same errno reads [Errno 101] Network is unreachable.

2. It is a plain OSError, not ConnectionError

import errno, socket
s = socket.socket()
try:
    s.connect(("1.1.1.1", 443))
except OSError as e:
    print(type(e).__mro__[:3])
    print("ConnectionError?", isinstance(e, ConnectionError))
    print("errno:", e.errno, errno.errorcode[e.errno], e.errno == errno.ENETUNREACH)
finally:
    s.close()

Output:

(<class 'OSError'>, <class 'Exception'>, <class 'BaseException'>)
ConnectionError? False
errno: 101 ENETUNREACH True

Python maps only some errnos to subclasses (ConnectionRefusedError for 111, ConnectionResetError for 104, and so on). ENETUNREACH is not one of them, so except ConnectionError will not catch it. Catch OSError and check e.errno == errno.ENETUNREACH.

3. With a hostname you usually see a DNS error first

import urllib.request
for url in ("http://example.com", "http://1.1.1.1"):
    try:
        urllib.request.urlopen(url, timeout=5)
    except Exception as e:
        print(url, "->", type(e).__name__, e)

Output:

http://example.com -> URLError <urlopen error [Errno -3] Try again>
http://1.1.1.1 -> URLError <urlopen error [Errno 101] Network unreachable>

Before connecting, urllib (and requests) must resolve the hostname. With no network, resolution fails first ([Errno -3] Try again on musl; glibc commonly gives Temporary failure in name resolution). So Errno 101 shows up when you connect to an IP literal, when DNS still works (for example via a local resolver or /etc/hosts) but routing does not, or when a hostname resolves to an IPv6 address on a host without IPv6.

4. Fixes

5. Retry only the network-down errors

import errno, socket, time

def connect(host, port, tries=3):
    for i in range(tries):
        try:
            return socket.create_connection((host, port), timeout=5)
        except OSError as e:
            if e.errno not in (errno.ENETUNREACH, errno.EHOSTUNREACH):
                raise
            print(f"try {i+1}: {e}; network down, retrying in {2**i}s")
            time.sleep(2**i)
    raise SystemExit("no network route; check the interface / VPN / docker network")

connect("1.1.1.1", 443)

Output:

try 1: [Errno 101] Network unreachable; network down, retrying in 1s
try 2: [Errno 101] Network unreachable; network down, retrying in 2s
try 3: [Errno 101] Network unreachable; network down, retrying in 4s
no network route; check the interface / VPN / docker network

The loop retries ENETUNREACH (101) and EHOSTUNREACH (113, No route to host) and re-raises everything else, so real bugs are not hidden. The output above is from the container with no network, so every try failed.

Related: Python errno codes list · socket error handling · Errno 111 connection refused.

Frequently asked questions

What does Errno 101 Network is unreachable mean in Python?

The OS has no route to the destination: no interface up, no default gateway, or no IPv6 connectivity for an IPv6 address.

Does except ConnectionError catch Errno 101?

No. Errno 101 (ENETUNREACH) is raised as a plain OSError. Catch OSError and check e.errno == errno.ENETUNREACH.

Why do I get a DNS error instead of Errno 101?

With a hostname, name resolution runs first and fails first when there is no network. Errno 101 appears for IP literals or when DNS still works.

Written with AI assistance. Measured on 2026-10-22 in the official python:3.11-alpine image run with docker --network none: raw socket connects over IPv4 and IPv6, the exception class and errno, urllib with a hostname vs an IP, and a retry loop. glibc wording checked with os.strerror(101) on Debian (Python 3.13.5). Every block was run verbatim and its output pasted unedited. PlainHeaders is our extension; Python is free.