embassy-rs/embassy · critical
PanicRawMutex locked from multiple contexts
Error message
PanicRawMutex locked from multiple contexts
What it means
PanicRawMutex is a raw mutex intended only for use inside panic handlers and other single-context settings; it does not block or spin. Its lock() detects double acquisition via an atomic flag and panics rather than waiting, because blocking inside a panic handler is forbidden.
Solutions
- Ensure PanicRawMutex-protected resources are only accessed from one context (the panic handler).
- Switch the shared resource to a blocking raw mutex (CriticalSectionRawMutex or ThreadModeRawMutex) if multiple contexts must share it.
- Add a re-entrancy guard or restructure code so the same mutex is never acquired twice on one call path.
Example fix
// before static CONSOLE: Console = Console::new(PanicRawMutex::INIT); // after (used from tasks + handlers) static CONSOLE: Console = Console::new(CriticalSectionRawMutex::INIT);
Defensive patterns
Strategy: validation
Validate before calling
// Audit call sites: only the panic handler may touch PanicRawMutex resources. // Prefer CriticalSectionRawMutex for anything shared across contexts.
Prevention
- Never share PanicRawMutex-backed statics with task or ISR code
- Use CriticalSectionRawMutex/ThreadModeRawMutex for multi-context data
- Avoid nested locking of the same raw mutex
- Document which context owns each mutex-protected resource
When it happens
Trigger: Calling lock() on a mutex backed by PanicRawMutex while it is already locked — e.g. the same static shared between a panic handler and normal code, or between two interrupt/NMI contexts, or re-entrant locking in one call path.
Common situations: Using a PanicRawMutex-backed channel/format shared with panic printing (defmt-panic / core::fmt buffering) from regular task code; nesting locks of the same mutex; accessing the shared resource in both an exception handler and mainline code.
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/dd1d634d797278e6.
Report an issue: GitHub.
Appendix: source
Thrown at embassy-sync/src/blocking_mutex/raw.rs:90
unsafe impl Send for PanicRawMutex {}
unsafe impl Sync for PanicRawMutex {}
impl PanicRawMutex {
/// Create a new `PanicRawMutex`.
pub const fn new() -> Self {
Self {
locked: AtomicBool::new(false),
}
}
}
unsafe impl RawMutex for PanicRawMutex {
const INIT: Self = Self::new();
fn lock<R>(&self, f: impl FnOnce() -> R) -> R {
#[cfg(target_has_atomic = "8")]
if self.locked.swap(true, Ordering::Relaxed) {
panic!("PanicRawMutex locked from multiple contexts")
}
#[cfg(not(target_has_atomic = "8"))]
critical_section::with(|_| {
if self.locked.load(Ordering::Acquire) {
panic!("PanicRawMutex locked from multiple contexts")
}
self.locked.store(true, Ordering::Release);
});
let ret = f();
self.locked.store(false, Ordering::Relaxed);
ret
}
}
// ================View on GitHub (pinned to 463a07b963)