tokio-rs/tokio · warning · io::Error
sender not available
Error message
sender not available
What it means
peek_sender_inner calls Socket::peek_sender() then converts via .as_socket(); when as_socket() returns None (the platform didn't populate a recognizable IPv4/IPv6 source), tokio returns this io::ErrorKind::Other error. The code comment notes that during testing this was only seen on macOS with a zero-sized receive buffer. It is a defensive guard for an ill-formed control message.
Source
Thrown at tokio/src/net/udp.rs:1892
/// It is important to be aware of this when designing your application-level protocol.
///
/// [packet injection attack]: https://en.wikipedia.org/wiki/Packet_injection
pub fn try_peek_sender(&self) -> io::Result<SocketAddr> {
self.io
.registration()
.try_io(Interest::READABLE, || self.peek_sender_inner())
}
#[inline]
fn peek_sender_inner(&self) -> io::Result<SocketAddr> {
self.io.try_io(|| {
self.as_socket()
.peek_sender()?
// May be `None` if the platform doesn't populate the sender for some reason.
// In testing, that only occurred on macOS if you pass a zero-sized buffer,
// but the implementation of `Socket::peek_sender()` covers that.
.as_socket()
.ok_or_else(|| io::Error::new(io::ErrorKind::Other, "sender not available"))
})
}
/// Gets the value of the `SO_BROADCAST` option for this socket.
///
/// For more information about this option, see [`set_broadcast`].
///
/// [`set_broadcast`]: method@Self::set_broadcast
pub fn broadcast(&self) -> io::Result<bool> {
self.io.broadcast()
}
/// Sets the value of the `SO_BROADCAST` option for this socket.
///
/// When enabled, this socket is allowed to send packets to a broadcast
/// address.
pub fn set_broadcast(&self, on: bool) -> io::Result<()> {
self.io.set_broadcast(on)View on GitHub (pinned to 625954f365)
Solutions
- Pass a non-zero buffer to peek_sender (the receive path still needs somewhere to put bytes).
- On macOS, use recv_from instead of peek_sender if you need the sender with a zero-byte probe.
- Handle io::ErrorKind::Other with this message as a soft failure — log and skip rather than tearing down the socket.
- Upgrade socket2/tokio to pick up any platform fixes for msg_name population.
Example fix
// before
let peer = sock.peek_sender().await?; // 'sender not available' on macOS
// after
let peer = match sock.peek_sender().await {
Ok(p) => p,
Err(e) if e.to_string() == "sender not available" => {
// fall back to a real recv to learn the peer
let mut buf = [0u8; 1];
let (_, p) = sock.recv_from(&mut buf).await?;
p
}
Err(e) => return Err(e.into()),
}; Defensive patterns
Strategy: try-catch
Validate before calling
// Pass a non-zero buffer to peek_sender; on macOS avoid zero-byte probes. // (No pure pre-check exists; guard at the call site.)
Type guard
fn is_sender_unavailable(e: &io::Error) -> bool {
e.kind() == io::ErrorKind::Other && e.to_string() == "sender not available"
} Try / catch
match sock.peek_sender().await {
Ok(p) => Ok(p),
Err(e) if e.to_string() == "sender not available" => {
let mut buf = [0u8; 1];
let (_, p) = sock.recv_from(&mut buf).await?;
Ok(p)
}
Err(e) => Err(e.into()),
} Prevention
- Always pass a non-zero buffer when probing the sender on macOS.
- Prefer recv_from over peek_sender for zero-byte probes on Apple platforms.
- Keep tokio and socket2 up to date for msg_name handling fixes.
- Treat this as a soft, platform-specific failure rather than fatal.
When it happens
Trigger: Calling UdpSocket::peek_sender() (or the underlying try_io) on a socket where the kernel returns a recvmsg ancillary sender that doesn't decode to an INET address. The doc note calls out macOS + zero-sized buffer as the observed cause.
Common situations: macOS only; passing a zero-length buffer to peek_sender; exotic platforms whose msg_name is malformed; ABI quirks in socket2 on specific macOS versions.
Related errors
- could not resolve to any address
- no addresses to send data to
- failed to write entire datagram to socket
- could not resolve to any address
- invalid address family (not IPv4 or IPv6)
AI-assisted analysis of tokio-rs/tokio@625954f365 (2026-08-11).
Data as JSON: /api/errors/20c77af8b695fdc7.
Report an issue: GitHub.