tokio-rs/tokio · error · io::Error
datagram cannot be called on a stream socket
Error message
datagram cannot be called on a stream socket
What it means
UnixSocket::datagram checks ty(); if it equals socket2::Type::STREAM, it returns io::ErrorKind::Other 'datagram cannot be called on a stream socket' before converting the fd into a UnixDatagram. A stream socket cannot be reinterpreted as a datagram socket, so tokio refuses. The doc notes this fires for new_stream-created sockets.
Source
Thrown at tokio/src/net/unix/socket.rs:232
}
let mio = {
use std::os::unix::io::{FromRawFd, IntoRawFd};
let raw_fd = self.inner.into_raw_fd();
unsafe { mio::net::UnixStream::from_raw_fd(raw_fd) }
};
UnixStream::connect_mio(mio).await
}
/// Converts the socket into a [`UnixDatagram`].
///
/// Calling this function on a socket created by [`new_stream`] will return an error.
///
/// [`new_stream`]: `UnixSocket::new_stream`
pub fn datagram(self) -> io::Result<UnixDatagram> {
if self.ty() == socket2::Type::STREAM {
return Err(io::Error::new(
io::ErrorKind::Other,
"datagram cannot be called on a stream socket",
));
}
let mio = {
use std::os::unix::io::{FromRawFd, IntoRawFd};
let raw_fd = self.inner.into_raw_fd();
unsafe { mio::net::UnixDatagram::from_raw_fd(raw_fd) }
};
UnixDatagram::from_mio(mio)
}
}
impl AsRawFd for UnixSocket {
fn as_raw_fd(&self) -> RawFd {
self.inner.as_raw_fd()View on GitHub (pinned to 625954f365)
Solutions
- If you need a UnixDatagram, construct with UnixSocket::new_datagram() and then call .datagram().
- Keep stream and datagram code paths separate so the conversion matches the construction.
- Add a type assertion (check ty() == Type::DGRAM) before calling .datagram() to fail with intent.
- Review the abstraction layer that wraps UnixSocket to ensure it routes by socket type.
Example fix
// before let s = UnixSocket::new_stream()?; let dg = s.datagram()?; // 'datagram cannot be called on a stream socket' // after let s = UnixSocket::new_datagram()?; s.bind(path)?; let dg = s.datagram()?;
Defensive patterns
Strategy: type-guard
Validate before calling
let s = UnixSocket::new_datagram()?; // for datagram conversion // If you have an existing fd, assert socket2::Type::DGRAM before .datagram().
Type guard
fn is_datagram_on_stream(e: &io::Error) -> bool {
e.kind() == io::ErrorKind::Other
&& e.to_string() == "datagram cannot be called on a stream socket"
} Try / catch
match sock.datagram() {
Ok(d) => Ok(d),
Err(e) if e.to_string() == "datagram cannot be called on a stream socket" => {
Err(anyhow::anyhow!("use new_datagram() to obtain a UnixDatagram"))
}
Err(e) => Err(e.into()),
} Prevention
- Construct with new_datagram() before calling .datagram().
- Keep stream and datagram code paths separate so conversion matches construction.
- Assert ty() == Type::DGRAM before calling .datagram() to fail with intent.
- Review wrapper abstractions to ensure they route by socket type.
When it happens
Trigger: Calling UnixSocket::datagram() on a socket created with UnixSocket::new_stream().
Common situations: Constructing a stream socket then trying to repurpose it as datagram; copy-paste across socket kinds; an abstraction that picks the wrong conversion method.
Related errors
- listen cannot be called on a datagram socket
- connect cannot be called on a datagram socket
- invalid address family (not IPv4 or IPv6)
- not a pipe
- not in O_WRONLY or O_RDWR access mode
AI-assisted analysis of tokio-rs/tokio@625954f365 (2026-08-11).
Data as JSON: /api/errors/d2bc088ddff120be.
Report an issue: GitHub.