tokio-rs/tokio · error · io::Error
no addresses to send data to
Error message
no addresses to send data to
What it means
UdpSocket::send_to resolves the destination, then calls addrs.next(); on None it returns this InvalidInput error directly (no iteration, no last_err). Unlike the bind/connect variants, send_to only ever tries the first resolved address — so an empty resolution is reported with this distinct message rather than 'could not resolve to any address.'
Source
Thrown at tokio/src/net/udp.rs:1190
/// use tokio::net::UdpSocket;
/// use std::io;
///
/// #[tokio::main]
/// async fn main() -> io::Result<()> {
/// let socket = UdpSocket::bind("127.0.0.1:8080").await?;
/// let len = socket.send_to(b"hello world", "127.0.0.1:8081").await?;
///
/// println!("Sent {} bytes", len);
///
/// Ok(())
/// }
/// ```
pub async fn send_to<A: ToSocketAddrs>(&self, buf: &[u8], addr: A) -> io::Result<usize> {
let mut addrs = to_socket_addrs(addr).await?;
match addrs.next() {
Some(target) => self.send_to_addr(buf, target).await,
None => Err(io::Error::new(
io::ErrorKind::InvalidInput,
"no addresses to send data to",
)),
}
}
/// Attempts to send data on the socket to a given address.
///
/// Note that on multiple calls to a `poll_*` method in the send direction, only the
/// `Waker` from the `Context` passed to the most recent call will be scheduled to
/// receive a wakeup.
///
/// # Return value
///
/// The function returns:
///
/// * `Poll::Pending` if the socket is not ready to write
/// * `Poll::Ready(Ok(n))` `n` is the number of bytes sent.View on GitHub (pinned to 625954f365)
Solutions
- Pre-resolve with tokio::net::lookup_host and require a non-empty result before sending.
- Send to a literal SocketAddr when the peer is known by IP.
- Treat as 'destination unavailable' and either retry after backoff or drop the datagram per policy.
- Cache resolved addresses for hot send loops to avoid re-resolving and to detect resolution regressions early.
Example fix
// before
let n = sock.send_to(payload, "collector.svc:8125").await?;
// after
let target = tokio::net::lookup_host("collector.svc:8125")
.await?.next()
.ok_or_else(|| anyhow::anyhow!("collector.svc unresolved"))?
.to_string();
let n = sock.send_to(payload, target.parse()?).await?; Defensive patterns
Strategy: validation
Validate before calling
let target = tokio::net::lookup_host((host.as_str(), port))
.await?.next()
.ok_or_else(|| anyhow::anyhow!("{host} resolved to no addresses"))?;
sock.send_to(buf, target).await? Type guard
fn is_empty_resolution(e: &io::Error) -> bool {
e.kind() == io::ErrorKind::InvalidInput && e.raw_os_error().is_none()
} Try / catch
match sock.send_to(buf, addr).await {
Ok(n) => Ok(n),
Err(e) if e.kind() == io::ErrorKind::InvalidInput && e.raw_os_error().is_none() => {
// no destination; drop or back off per policy
Ok(0)
}
Err(e) => Err(e.into()),
} Prevention
- Pre-resolve the destination for hot send paths and cache it.
- Send to a literal SocketAddr when the peer is known by IP.
- Treat empty resolution as 'destination unavailable' and apply backoff or drop policy.
- Log unresolved destinations to surface DNS regressions.
When it happens
Trigger: Calling UdpSocket::send_to(buf, "host:port") where to_socket_addrs yields an empty iterator (no A/AAAA records). The match arm None fires immediately.
Common situations: Sending a datagram to a misspelled or unresolvable hostname; service-discovery entry with no records; transient DNS failure returning empty; sending to a name with only a CNAME chain that bottoms out.
Related errors
- could not resolve to any address
- could not resolve to any address
- could not resolve to any address
- sender not available
- failed to write entire datagram to socket
AI-assisted analysis of tokio-rs/tokio@625954f365 (2026-08-11).
Data as JSON: /api/errors/c15ad4ed6037631b.
Report an issue: GitHub.