n0-computer/iroh · critical · io::Error
NetworkDown
NetworkDown
Error message
All transports failed to receive
What it means
The QUIC socket's transport poll_recv loop hit MAX_CONSECUTIVE_RECV_ERRORS consecutive receive failures across all transports. The endpoint concludes the network is down, returns io::ErrorKind::NetworkDown, and shuts the QUIC endpoint down rather than spinning forever on errors.
Solutions
- Recreate/restart the Endpoint (and its sockets) when NetworkDown is returned; it is designed to signal a full teardown.
- Diagnose why the underlying transports fail to recv: check interface state, permissions, and firewall rules.
- Retry application-level connection attempts with backoff after the network recovers.
- Monitor the warn! log ('All transports failed to receive') to correlate with environment changes.
Example fix
// before
let conn = endpoint.connect(addr, alpn).await?; // fails after NetworkDown teardown
// after
match endpoint.connect(addr, alpn).await {
Ok(c) => c,
Err(e) if e.kind() == NetworkDown => { endpoint = recreate_endpoint().await?; endpoint.connect(addr, alpn).await? }
Err(e) => return Err(e.into()),
} Defensive patterns
Strategy: retry
Type guard
fn is_network_down(e: &std::io::Error) -> bool { e.kind() == std::io::ErrorKind::NetworkDown } Try / catch
match ep_transport_recv() {
Err(e) if e.kind() == std::io::ErrorKind::NetworkDown => { rebuild_endpoint_with_backoff().await?; }
other => other?,
} Prevention
- Monitor interface changes (suspend/resume, VPN) and proactively rebuild sockets.
- Use exponential backoff when recreating the endpoint.
- Alert on the 'All transports failed to receive' warning log.
- Test app behavior in degraded-network environments.
When it happens
Trigger: poll_recv repeatedly returning errors for every transport (relay and UDP) MAX_CONSECUTIVE_RECV_ERRORS times in a row — e.g. sockets closed underneath, OS network interface flapping, all underlying transports erroring on recv.
Common situations: Laptop suspending/resuming or interface changes killing UDP sockets, containers losing their network namespace, firewall/VPN changes breaking all local transports, running in environments where UDP is blocked and the relay transport also fails.
Related errors
- NoObservedAddr
- NotConnected
- The relay is rate-limiting this endpoint; outbound relay…
- Only a single default address can be set per IP family
- Invalid transport configuration
AI-assisted analysis of n0-computer/iroh@2b4de030ce (2026-09-08).
Data as JSON: /api/errors/7a1608d34c23ddbd.
Report an issue: GitHub.
Appendix: source
Thrown at iroh/src/socket/transports.rs:351
for transport in self.relay.iter_mut().rev() {
poll_transport!(transport);
}
#[cfg(not(wasm_browser))]
for transport in self.ip.iter_mut() {
poll_transport!(transport);
}
}
if total_polled == total_errors {
// All transports errored.
self.consecutive_total_recv_failures += 1;
debug!(
"All transports failed to receive ({} remaining)",
MAX_CONSECUTIVE_RECV_ERRORS.wrapping_sub(self.consecutive_total_recv_failures)
);
if self.consecutive_total_recv_failures >= MAX_CONSECUTIVE_RECV_ERRORS {
warn!("All transports failed to receive. QUIC endpoint will be shutdown.");
Poll::Ready(Err(io::Error::new(
io::ErrorKind::NetworkDown,
"All transports failed to receive",
)))
} else {
Poll::Ready(Ok(0))
}
} else {
// At least one transport is pending or returned Ok(0).
self.consecutive_total_recv_failures = 0;
if return_ready {
Poll::Ready(Ok(0))
} else {
Poll::Pending
}
}
}
/// Returns a list of all currently known local addresses.View on GitHub (pinned to 2b4de030ce)