embassy-rs/embassy · error

unwrap of ` ` failed

Error message

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

What it means

This panic comes from embassy-net-wiznet's internal `unwrap!` macro (the non-defmt variant) when the expression passed to `unwrap!(...)` is an `Err` or `None`. The macro converts the value via `fmt::Try::into_result` and, on failure, panics with the stringified expression and the debug-formatted error. It is a deliberate fail-fast on operations the driver assumed could not fail or that the caller was expected to handle.

Solutions

  1. Identify the real `unwrap!` call site: the panic string includes the stringified expression; search embassy-net-wiznet/src for that expression.
  2. Fix the underlying cause (usually SPI bus errors, wrong chip-select/speed wiring, or missing device reset) rather than the unwrap itself.
  3. Enable the `defmt` feature if you want `defmt::unwrap!` semantics and richer logging in embedded builds.
  4. As a last resort, fork/patch the driver to propagate the error instead of unwrapping.

Example fix

// before: driver panics inside unwrap!
let res = unwrap!(self.spi.read_write(&mut buf[..]), "spi read_write");
// after: propagate SPI errors instead of panicking
let res = self.spi.read_write(&mut buf[..]).map_err(|_| Error::Spi)?;
Defensive patterns

Strategy: try-catch

Validate before calling

// In no_std/panic=abort firmware you cannot catch; pre-validate hardware state:
if !self.device_ready() { return Err(Error::Spi); }

Type guard

fn is_ok<T, E>(r: &Result<T, E>) -> bool { r.is_ok() }

Try / catch

// Firmware: set a panic hook to log the unwrap expression and reset/defuse.
#[panic_handler] or `panic_hook`: log panic info, then reset the W5500 and reinit SPI.

Prevention

When it happens

Trigger: Any call to `unwrap!(expr)` in the wiznet driver where `expr: Result<T,E>` is `Err(e)` or `expr: Option<T>` is `None` — e.g. unwrapping SPI transfer results, buffer queue pops, or device register reads during W5500 Ethernet chip operations.

Common situations: Bare-metal/embassy firmware using the Wiznet W5500 driver where an SPI transaction failed, the chip was miswired/reset, or an internal buffer/queue returned None. Because this is the `not(feature = "defmt")` build, the panic message prints via core fmt instead of defmt.

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

Appendix: source

Thrown at embassy-net-wiznet/src/fmt.rs:189

    };
}

#[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)