← index #1078Issue #18797
Related · high · value 1.099
QUERY · ISSUE

requests: guard against getaddrinfo() hang when WiFi not connected

openby paul-matthewsopened 2026-02-09updated 2026-02-10

Summary

The request() function in requests/__init__.py calls socket.getaddrinfo() (line 81) without verifying network connectivity. On platforms where getaddrinfo() blocks indefinitely when the WiFi interface is active but not connected (see micropython/micropython#18797), this causes the device to freeze with no way to recover except a hard reset.

The timeout parameter passed to requests.get() has no effect because socket.settimeout() is applied to the socket object (line 93) — which is created after getaddrinfo() returns. So the hang occurs before any timeout takes effect.

Suggested fix

Add a connectivity check before getaddrinfo():

    # Guard: getaddrinfo() blocks indefinitely on RP2040/RP2350 when the
    # CYW43 WiFi interface is active but has no IP address.
    try:
        import network
        _wlan = network.WLAN(network.STA_IF)
        if not _wlan.isconnected():
            raise OSError(-1, "WiFi not connected")
    except ImportError:
        pass  # Non-WiFi platform, skip guard

    ai = socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM)

This is wrapped in try/except ImportError so it's safe on non-WiFi platforms (ESP32 Ethernet, Unix port, etc.).

Also consider

A default socket timeout (e.g., 30s) applied before getaddrinfo() would provide defense-in-depth, though it wouldn't help here since settimeout() only affects socket operations, not DNS resolution.

Environment

  • Board: Raspberry Pi Pico 2 W (RP2350 + CYW43)
  • MicroPython: v1.26.1
  • Upstream issue: micropython/micropython#18797
1 comment
dpgeorge · 2026-02-10

This needs to be fixed properly in socket.getaddrinfo() so it doesn't block indefinitely.

CANDIDATE · ISSUE

socket.getaddrinfo() blocks indefinitely when WiFi active but not connected (RP2350/CYW43)

closedby paul-matthewsopened 2026-02-09updated 2026-03-04
extmod

Summary

socket.getaddrinfo() blocks indefinitely on RP2350 (Pico 2 W) when the CYW43 WiFi interface is active (wlan.active(True)) but has no IP address (not yet connected, or connect() still in progress). No timeout is applied, and the call never returns. The device becomes completely unresponsive — no serial output, no exception, no way to recover except a hard reset.

This makes it impossible to write robust networked applications that handle WiFi disconnection gracefully, since any DNS lookup during a WiFi gap will freeze the entire runtime.

Reproduction

# repro_getaddrinfo_hang.py — Raspberry Pi Pico 2 W
# Demonstrates that getaddrinfo() hangs when WiFi is active but not connected.
# Run immediately after boot (before WiFi has connected).

import network
import socket
import time

def run_test():
    wlan = network.WLAN(network.STA_IF)

    # Test 1: WiFi not activated — getaddrinfo fails fast
    wlan.active(False)
    time.sleep(0.5)
    print(f"Test 1: active={wlan.active()}, connected={wlan.isconnected()}")
    try:
        print("  Calling getaddrinfo()...")
        ai = socket.getaddrinfo("example.com", 443, 0, socket.SOCK_STREAM)
        print(f"  Result: {ai[0][-1]}")
    except OSError as e:
        print(f"  OSError: {e}")  # Expected: fails fast with error code -2

    # Test 2: WiFi activated, not connected — getaddrinfo HANGS
    wlan.active(True)
    time.sleep(1)
    print(f"\nTest 2: active={wlan.active()}, connected={wlan.isconnected()}")
    print("  Calling getaddrinfo()...")
    print("  >>> If output stops here, getaddrinfo() is blocking indefinitely <<<")
    try:
        ai = socket.getaddrinfo("example.com", 443, 0, socket.SOCK_STREAM)
        print(f"  Result: {ai[0][-1]}")
    except OSError as e:
        print(f"  OSError: {e}")

    print("\nBoth tests completed without hanging.")

run_test()

Expected behavior

getaddrinfo() should return an error (e.g., OSError with EAI_FAIL or similar) within a reasonable timeout when the network interface has no IP address.

Actual behavior

  • WiFi not active (wlan.active(False)): getaddrinfo() fails immediately with OSError: -2 — correct behavior.
  • WiFi active, not connected (wlan.active(True), no connect() called): getaddrinfo() blocks indefinitely. The call never returns. No timeout, no exception. The device is completely frozen.

Analysis

The issue appears to be in the lwIP DNS resolver. When the WiFi interface is active, lwIP considers the interface "up" and attempts DNS resolution. But with no IP address and no default gateway, the DNS query is sent into the void and lwIP waits for a response that never comes. There is no timeout applied at the getaddrinfo() level.

When the interface is inactive (wlan.active(False)), lwIP correctly determines there is no available interface and fails fast.

Impact

This affects any MicroPython application using requests.get(), urequests.get(), or raw socket.getaddrinfo() on Pico W / Pico 2 W during WiFi connection gaps. The requests module calls getaddrinfo() before connect() or wrap_socket(), so even applications that guard TLS calls will hang at the DNS stage.

The timeout parameter passed to requests.get() has no effect because socket.settimeout() is not applied until after the socket is created — which happens after getaddrinfo().

Environment

  • Board: Raspberry Pi Pico 2 W (RP2350 + CYW43)
  • MicroPython: v1.26.1
  • Pico SDK: 2.1.1
  • Build: Pimoroni Cosmic Unicorn board variant (custom build from pimoroni/unicorn repo, micropython/1.26.0 branch)

Suggested fix

Option A: Apply a timeout to the lwIP DNS query in socket_getaddrinfo() (extmod/modsocket.c), so it fails with OSError after a bounded time.

Option B: Check interface state (has IP address) before initiating DNS resolution and fail immediately if the interface has no network path.

Keyboard

j / / n
next pair
k / / p
previous pair
1 / / h
show query pane
2 / / l
show candidate pane
c
copy suggested comment
r
toggle reasoning
g i
go to index
?
show this help
esc
close overlays

press ? or esc to close

copied