embassy-rs/embassy · error

ipv6 support not enabled

Error message

ipv6 support not enabled

What it means

This panic is emitted when an application calls TcpConnector::connect with a remote address of type IpAddr::V6 while the embassy-net crate was compiled without the `ipv6` feature. embassy-net only instantiates address conversion code for the address families actually enabled via cargo features, so an IPv6 address cannot be represented and the library deliberately panics instead of silently failing. It is a build-configuration error, not a runtime condition that can be recovered from.

Solutions

  1. Add the `ipv6` feature to embassy-net in Cargo.toml: `embassy-net = { version = "...", features = ["ipv6"] }`
  2. Filter resolved addresses to IPv4 only when ipv6 support is not compiled in
  3. Verify the feature is actually activated (check `cargo tree -f '{p} {f}'` for embassy-net) — it may be disabled by a dependency's default-features choice

Example fix

// before (Cargo.toml)
embassy-net = { version = "0.6", features = ["tcp"] }
// after
embassy-net = { version = "0.6", features = ["tcp", "ipv6"] }
Defensive patterns

Strategy: validation

Validate before calling

fn ensure_supported(addr: core::net::IpAddr) -> core::net::IpAddr {
    if matches!(addr, core::net::IpAddr::V6(_)) && !cfg!(feature = "ipv6") {
        panic!("ipv6 not enabled in embassy-net; build with the ipv6 feature");
    }
    addr
}
// call before connect: let addr = ensure_supported(remote.ip());

Type guard

fn is_ipv4(addr: core::net::IpAddr) -> bool { matches!(addr, core::net::IpAddr::V4(_)) }

Prevention

When it happens

Trigger: Calling `TcpConnector::connect` on an embassy-net stack with a `SocketAddr`/`IpAddr` in the V6 variant while the crate was built without `features = ["ipv6"]`. Typical when resolving a hostname that returns an AAAA record and using the v6 result first.

Common situations: Developer enables dual-stack at the application level but forgets the `ipv6` feature on embassy-net in Cargo.toml; a DNS resolver returns an IPv6 address first; code was ported from std where Ipv6Addr always exists.

Related errors


AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10). Data as JSON: /api/errors/82bbbff9cc47a296. Report an issue: GitHub.

Appendix: source

Thrown at embassy-net/src/tcp.rs:1344

    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`].
    ///
    /// `'a` is the lifetime of the borrow of the [`TcpClient`] (whose pool the
    /// connection's buffers come from), `'d` the lifetime of the stack.
    pub struct TcpConnection<'a, 'd, const N: usize, const TX_SZ: usize, const RX_SZ: usize> {

View on GitHub (pinned to 463a07b963)