embassy-rs/embassy · error

unwrap of ` ` failed

Error message

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

What it means

This is the annotated variant of embassy-net's `unwrap!` macro (non-defmt build): `unwrap!(expr, "message", args...)`. On `Err`/`None` it panics with the stringified expression, the caller-provided context message (via `format_args!`), and the debug-formatted error. The extra message text identifies which internal operation failed.

Solutions

  1. Use the context message in the panic output to pinpoint the failing `unwrap!(..., "ctx")` call in embassy-net sources.
  2. Fix the root cause: enlarge socket/resource pools (`StackResources`), ensure sockets are not used after close, and check task wiring.
  3. Enable the `defmt` feature for richer logging on target hardware.
  4. Patch the driver locally to propagate the error rather than unwrap if failures are expected in your deployment.

Example fix

// before
let slot = unwrap!(self.sockets.get(handle), "get socket slot");
// after
let slot = self.sockets.get(handle).ok_or(Error::SocketClosed)?;
Defensive patterns

Strategy: validation

Validate before calling

// Validate resource availability before operations that internally unwrap:
if self.stack_resources_exhausted() { return Err(Error::ConnectionReset); }

Type guard

fn socket_is_open(s: &embassy_net::tcp::TcpSocket<'_>) -> bool { !matches!(s.state(), embassy_net::tcp::State::Closed) }

Try / catch

// Panic hook that captures the context message plus expression, then triggers a controlled restart of the network stack; panics cannot be caught in no_std firmware.

Prevention

When it happens

Trigger: Any `unwrap!(expr, "ctx", ...)` call inside embassy-net whose `expr` evaluates to `Err(e)` or `None` — this macro arm (fmt.rs:210) fires only when extra context arguments are supplied at the call site.

Common situations: Embassy firmware running the embassy-net stack where an internal operation (queue send/receive, socket bookkeeping) fails while carrying a context label; typically seen during buffer starvation, closed resources, or race-y socket teardown.

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/dee26cec36ed494c. Report an issue: GitHub.

Appendix: source

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

    };
}

#[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;
    type Error;
    fn into_result(self) -> Result<Self::Ok, Self::Error>;
}

impl<T> Try for Option<T> {
    type Ok = T;
    type Error = NoneError;

View on GitHub (pinned to 463a07b963)