embassy-rs/embassy · error

unwrap of ` ` failed

Error message

unwrap of `{}` failed: {:?}

What it means

This panic originates from embassy-net's internal `unwrap!` macro (the non-defmt variant) defined in src/fmt.rs. It converts its argument via `fmt::Try::into_result` (works for both `Result` and `Option`) and panics with the stringified expression plus the debug-formatted error when the value is `Err` or `None`. It marks a fail-fast on an operation the stack implementation treats as unrecoverable/assumed-infallible.

Solutions

  1. Locate the failing call: the panic message prints the stringified expression; search embassy-net/src for that `unwrap!(...)` site.
  2. Address the root cause — commonly resource capacity issues (increase packet/socket buffer counts in `Config`) or a closed channel/socket being used.
  3. Enable the `defmt` feature for `defmt::unwrap!` and better embedded logging.
  4. Patch the call site to return an error (e.g. `Error::ConnectionReset` style) if the failure is environment-dependent.

Example fix

// before: internal unwrap panics on closed channel
let pkt = unwrap!(self.rx_chan.receive().await);
// after: return an error instead of panicking
let pkt = self.rx_chan.receive().await.map_err(|_| Error::ConnectionReset)?;
Defensive patterns

Strategy: validation

Validate before calling

// Size resources generously so internal unwraps never see empty/full queues:
let resources = embassy_net::StackResources::<8>::new(); // > expected concurrent sockets
// And check socket state before use:
if socket.state() == embassy_net::tcp::State::Closed { /* reopen */ }

Type guard

fn has_capacity<T>(q: &embassy_sync::channel::Channel<'_, T, N>, n: usize) -> bool { q.try_send(unsafe { core::mem::MaybeUninit::zeroed().assume_init() }).is_ok() } // prefer explicit capacity accounting

Try / catch

// Install a panic hook to log the unwrap expression and task context, then restart the network task (or soft-reset) since panics abort in embedded targets.

Prevention

When it happens

Trigger: Any `unwrap!(expr)` inside embassy-net where `expr` is an `Err(e)` or `None` — e.g. internal channel/queue operations, socket-state lookups, or mDNS/DHCP-related unwraps during network stack execution.

Common situations: Rust embedded (embassy) firmware using the embassy-net TCP/UDP stack: a resource queue returned None (capacity exhausted or closed) or an internal operation failed, panicking the firmware task instead of returning an error.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


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

Appendix: source

Thrown at embassy-net/src/fmt.rs:202

    };
}

#[cfg(feature = "defmt")]
#[collapse_debuginfo(yes)]
macro_rules! unwrap {
    ($($x:tt)*) => {
        ::defmt::unwrap!($($x)*)
    };
}

#[cfg(not(feature = "defmt"))]
#[collapse_debuginfo(yes)]
macro_rules! unwrap {
    ($arg:expr) => {
        match $crate::fmt::Try::into_result($arg) {
            ::core::result::Result::Ok(t) => t,
            ::core::result::Result::Err(e) => {
                ::core::panic!("unwrap of `{}` failed: {:?}", ::core::stringify!($arg), e);
            }
        }
    };
    ($arg:expr, $($msg:expr),+ $(,)? ) => {
        match $crate::fmt::Try::into_result($arg) {
            ::core::result::Result::Ok(t) => t,
            ::core::result::Result::Err(e) => {
                ::core::panic!("unwrap of `{}` failed: {}: {:?}", ::core::stringify!($arg), ::core::format_args!($($msg,)*), e);
            }
        }
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct NoneError;

pub trait Try {
    type Ok;

View on GitHub (pinned to 463a07b963)