embassy-rs/embassy · error
unwrap of ` ` failed
Error message
unwrap of `{}` failed: {}: {:?} What it means
This panic comes from the embassy-nxp `unwrap!` macro, which wraps a `Result`- or `Option`-returning expression and panics when it holds an error variant. The library throws it instead of `.unwrap()` so the panic message includes the caller-supplied context message plus the debug-formatted error value. Any call site that uses `unwrap!(expr, "context")` on a failing expression triggers it.
Solutions
- Read the `: {:?}` debug output at the end of the panic to identify the underlying error variant
- Find the call site via the stringified expression in the panic message and handle the Result with `?` or a match instead of unwrapping
- Fix the root cause the inner error reports (wrong peripheral config, busy hardware, missing init) before retrying
- If the expression is an Option that should never be None, add an explicit assert with a domain-specific message
Example fix
// before
let status = unwrap!(i2c.blocking_write_read(addr, ®, &mut buf), "read failed");
// after
let status = match i2c.blocking_write_read(addr, ®, &mut buf) {
Ok(s) => s,
Err(e) => { defmt::error!("read failed: {:?}", e); return Err(e); }
}; Defensive patterns
Strategy: validation
Validate before calling
fn unwrap_ok<T, E: core::fmt::Debug>(r: Result<T, E>) -> T { match r { Ok(t) => t, Err(e) => { defmt::error!("unwrap failed: {:?}", e); unreachable!() } } } // prefer handling Err explicitly before calling unwrap!
Type guard
fn is_ok<T, E>(r: &Result<T, E>) -> bool { r.is_ok() }
Try / catch
// Rust panics are not catchable per-call; use panic = "abort" awareness or catch_unwind on std targets let v = std::panic::catch_unwind(|| unwrap!(fallible(), "ctx"));
Prevention
- Never unwrap fallible HAL calls in production firmware; propagate with ?
- Use the macro's context message parameter to aid debugging
- Log the inner error's Debug output before any unwrap
- Prefer explicit match/ok_or over the unwrap macro
When it happens
Trigger: Calling `unwrap!(some_result, "message")` in embassy-nxp code (or user code using the exported macro) where the expression resolves to `Err(e)` via `fmt::Try::into_result`, or `None` for Options.
Common situations: Peripheral drivers encountering unexpected hardware states (failed init, NACKed I2C transactions, timeout results) that were force-unwrapped; drivers written for a Result-returning API being ported to a version where the call now returns an error type.
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
- unwrap of ` ` failed
- Can only take the executor once
- Invalid FilterConfig (TooManyFilters)! A FilterConfig must…
- Invalid FilterConfig (EmptyFilterConfig)! A FilterConfig…
- Clocks have not been initialized
AI-assisted analysis of embassy-rs/embassy@463a07b963 (2026-09-10).
Data as JSON: /api/errors/577da8b76fa8c58e.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-nxp/src/fmt.rs:223
};
}
#[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)