embassy-rs/embassy · error
ipv4 support not enabled
Error message
ipv4 support not enabled
What it means
`TcpClient::connect` (the `embedded_nal_async::TcpConnect` impl in embassy-net) converts a `core::net::SocketAddr` to the stack's wire `IpAddress`. When the remote address is IPv4 but the `ipv4` cargo feature is disabled, no arm exists to build the address and the code panics with "ipv4 support not enabled". It is a compile-time feature misconfiguration surfaced as a runtime panic.
Solutions
- Enable the `ipv4` feature on the embassy-net dependency in Cargo.toml.
- Alternatively, connect to an IPv6 address so the `ipv6` arm is used, if the target network supports it.
- Check the address at runtime before calling `connect` and return your own error for unsupported families.
- Verify the resolved feature set with `cargo tree -e features -p embassy-net` in case another crate's default features disabled it.
Example fix
// before
embassy-net = { version = "0.4", features = ["ipv6"] }
let conn = client.connect("192.168.1.10:8080".parse().unwrap()).await?; // panics
// after
embassy-net = { version = "0.4", features = ["ipv4"] }
let conn = client.connect("192.168.1.10:8080".parse().unwrap()).await?; Defensive patterns
Strategy: validation
Validate before calling
// Check address family against enabled features before connecting:
fn addr_supported(remote: core::net::SocketAddr) -> bool {
match remote.ip() {
IpAddr::V4(_) => cfg!(feature = "ipv4"), // check via your own build cfg constants
IpAddr::V6(_) => cfg!(feature = "ipv6"),
}
}
// Usage: if !addr_supported(remote) { return Err(MyErr::UnsupportedFamily); } Type guard
fn is_v4(remote: &core::net::SocketAddr) -> bool { matches!(remote, core::net::SocketAddr::V4(_)) } Try / catch
// Connect in a wrapper that validates first; in firmware panics cannot be caught, so never call connect with an unsupported family:
match addr { SocketAddr::V4(_) if !CFG_IPV4 => Err(MyError::UnsupportedFamily), _ => client.connect(addr).await } Prevention
- Always enable both `ipv4` and `ipv6` features unless the target network is guaranteed single-family.
- Add a compile-time assertion: `const _: () = assert!(cfg!(feature = "ipv4"));` when your code only dials IPv4.
- Parse addresses and check `is_ipv4()`/`is_ipv6()` before calling connect.
- Review embassy-net feature flags after every dependency upgrade.
When it happens
Trigger: Calling `TcpClient::connect` (via the embedded-nal-async trait) with a `SocketAddr::V4(...)` remote while embassy-net was built without `features = ["ipv4"]`.
Common situations: Embedded Rust projects that connect to a hard-coded IPv4 address (e.g. "192.168.1.10:8080") but enabled only the `ipv6` feature (or neither) in embassy-net's Cargo feature list; often after upgrading embassy-net or copying a config tuned for IPv6-only networks.
Related errors
- unwrap of ` ` failed
- unwrap of ` ` failed
- Can only take the executor once
- DMA data error
- MCLK frequency < 9.5 MHz is not compatible with the TRNG
AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10).
Data as JSON: /api/errors/9408cba966c21cf5.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-net/src/tcp.rs:1340
self.socket_timeout = timeout;
}
}
impl<'d, const N: usize, const TX_SZ: usize, const RX_SZ: usize> embedded_nal_async::TcpConnect
for TcpClient<'d, N, TX_SZ, RX_SZ>
{
type Error = Error;
type Connection<'m>
= TcpConnection<'m, 'd, N, TX_SZ, RX_SZ>
where
Self: 'm;
async fn connect<'a>(&'a self, remote: core::net::SocketAddr) -> Result<Self::Connection<'a>, Self::Error> {
let addr: crate::wire::IpAddress = match remote.ip() {
#[cfg(feature = "ipv4")]
IpAddr::V4(addr) => crate::wire::IpAddress::Ipv4(addr),
#[cfg(not(feature = "ipv4"))]
IpAddr::V4(_) => panic!("ipv4 support not enabled"),
#[cfg(feature = "ipv6")]
IpAddr::V6(addr) => crate::wire::IpAddress::Ipv6(addr),
#[cfg(not(feature = "ipv6"))]
IpAddr::V6(_) => panic!("ipv6 support not enabled"),
};
let remote_endpoint = (addr, remote.port());
let mut socket = TcpConnection::new(self.stack, self.state)?;
socket.socket.set_timeout(self.socket_timeout);
socket
.socket
.connect(remote_endpoint)
.await
.map_err(|_| Error::ConnectionReset)?;
Ok(socket)
}
}
/// Opened TCP connection in a [`TcpClient`].View on GitHub (pinned to 463a07b963)