tokio-rs/tokio · error · io::Error
could not resolve to any address
Error message
could not resolve to any address
What it means
TcpStream::connect resolves via to_socket_addrs, tries connect_addr on each, and uses unwrap_or_else to build this InvalidInput error only when last_err is None — meaning the resolved address iterator was empty. If candidates existed, the last connect error propagates instead. So this specific message means 'resolution returned no addresses to try.'
Source
Thrown at tokio/src/net/tcp/stream.rs:131
///
/// The [`write_all`] method is defined on the [`AsyncWriteExt`] trait.
///
/// [`write_all`]: fn@crate::io::AsyncWriteExt::write_all
/// [`AsyncWriteExt`]: trait@crate::io::AsyncWriteExt
pub async fn connect<A: ToSocketAddrs>(addr: A) -> io::Result<TcpStream> {
let addrs = to_socket_addrs(addr).await?;
let mut last_err = None;
for addr in addrs {
match TcpStream::connect_addr(addr).await {
Ok(stream) => return Ok(stream),
Err(e) => last_err = Some(e),
}
}
Err(last_err.unwrap_or_else(|| {
io::Error::new(
io::ErrorKind::InvalidInput,
"could not resolve to any address",
)
}))
}
/// Establishes a connection to the specified `addr`.
async fn connect_addr(addr: SocketAddr) -> io::Result<TcpStream> {
let sys = mio::net::TcpStream::connect(addr)?;
TcpStream::connect_mio(sys).await
}
pub(crate) async fn connect_mio(sys: mio::net::TcpStream) -> io::Result<TcpStream> {
let stream = TcpStream::new(sys)?;
// Once we've connected, wait for the stream to be writable as
// that's when the actual connection has been initiated. Once we're
// writable we check for `take_socket_error` to see if the connectView on GitHub (pinned to 625954f365)
Solutions
- Pre-resolve with tokio::net::lookup_host to confirm addresses exist before connecting.
- Use happy-eyeballs / iterate the resolved list yourself to keep going past individual failures.
- Distinguish empty-resolution from connect-refused: empty → InvalidInput with no raw os error; refused → raw os error.
- Verify DNS externally (dig +short host) and fix or update the resolver.
Example fix
// before
let s = TcpStream::connect("svc.example:443").await?;
// after
let addrs: Vec<_> = tokio::net::lookup_host("svc.example:443").await?.collect();
if addrs.is_empty() {
return Err(anyhow::anyhow!("svc.example resolved to no addresses"));
}
let mut last = None;
for a in addrs {
match TcpStream::connect(a).await { Ok(s) => break Ok(s), Err(e) => last = Some(e) }
} Defensive patterns
Strategy: validation
Validate before calling
let addrs: Vec<_> = tokio::net::lookup_host((host.as_str(), port)).await?.collect();
if addrs.is_empty() {
return Err(anyhow::anyhow!("{host} resolved to no addresses"));
}
let mut last = None;
for a in addrs {
match TcpStream::connect(a).await { Ok(s) => return Ok(s), Err(e) => last = Some(e) }
}
Err(last.unwrap().into()) Type guard
fn is_empty_resolution(e: &io::Error) -> bool {
e.kind() == io::ErrorKind::InvalidInput && e.raw_os_error().is_none()
} Try / catch
match TcpStream::connect(addr).await {
Ok(s) => Ok(s),
Err(e) if e.kind() == io::ErrorKind::InvalidInput && e.raw_os_error().is_none() => {
Err(anyhow::anyhow!("no addresses resolved for {addr}"))
}
Err(e) => Err(e.into()),
} Prevention
- Pre-resolve and iterate addresses yourself to keep connecting past failures.
- Use literal IPs for known peers to avoid DNS ambiguity.
- Distinguish empty resolution (no raw os error) from connect-refused (raw os error).
- Refresh DNS periodically for long-lived connection pools.
When it happens
Trigger: Calling TcpStream::connect("host:port") where the hostname resolves to an empty A/AAAA set. The for loop never runs, last_err is None, and the fallback fires.
Common situations: Connecting to a typo'd or decommissioned hostname; bare CNAME with no A record; resolver / /etc/hosts returning an empty answer; a stale service-discovery entry pointing at a name with no records.
Related errors
- could not resolve to any address
- invalid address family (not IPv4 or IPv6)
- could not resolve to any address
- no addresses to send data to
- sender not available
AI-assisted analysis of tokio-rs/tokio@625954f365 (2026-08-11).
Data as JSON: /api/errors/52429914145aa943.
Report an issue: GitHub.