leptos-rs/leptos · error
lock poisoned
Error message
lock poisoned
What it means
or_poisoned's OrPoisoned trait converts the Err(PoisonError) of a RwLock read-lock attempt into a panic via expect("lock poisoned"). This happens when another thread panicked while holding the RwLock write guard, leaving the lock poisoned; instead of propagating PoisonError, the library treats a poisoned lock as an unrecoverable internal invariant and panics.
Source
Thrown at or_poisoned/src/lib.rs:44
pub trait OrPoisoned {
/// The inner guard type.
type Inner;
/// Unwraps the lock.
///
/// ## Panics
///
/// Will panic if the lock is poisoned.
fn or_poisoned(self) -> Self::Inner;
}
impl<'a, T: ?Sized> OrPoisoned
for Result<RwLockReadGuard<'a, T>, PoisonError<RwLockReadGuard<'a, T>>>
{
type Inner = RwLockReadGuard<'a, T>;
fn or_poisoned(self) -> Self::Inner {
self.expect("lock poisoned")
}
}
impl<'a, T: ?Sized> OrPoisoned
for Result<RwLockWriteGuard<'a, T>, PoisonError<RwLockWriteGuard<'a, T>>>
{
type Inner = RwLockWriteGuard<'a, T>;
fn or_poisoned(self) -> Self::Inner {
self.expect("lock poisoned")
}
}
impl<'a, T: ?Sized> OrPoisoned for LockResult<MutexGuard<'a, T>> {
type Inner = MutexGuard<'a, T>;
fn or_poisoned(self) -> Self::Inner {
self.expect("lock poisoned")View on GitHub (pinned to 32d20f6c9d)
Solutions
- Find and fix the original panic that poisoned the lock — the "lock poisoned" panic is secondary; the first panic's backtrace is the root cause.
- Catch panics in update/effect closures (std::panic::catch_unwind or Leptos error boundaries) so they never panic while holding a write lock.
- Minimize the code running under write locks to reduce panic windows.
- If a poisoned state is legitimately recoverable, avoid or_poisoned and handle PoisonError manually (into_inner to recover data).
Example fix
// before
let guard = lock.write().or_poisoned();
// after
let guard = match lock.write() {
Ok(g) => g,
Err(poisoned) => poisoned.into_inner(), // recover data despite poison
}; Defensive patterns
Strategy: try-catch
Validate before calling
if lock.is_poisoned() {
// recover or restart before reading
} Type guard
fn lock_healthy<T>(lock: &RwLock<T>) -> bool {
!lock.is_poisoned()
} Try / catch
let guard = match lock.read() {
Ok(g) => g,
Err(p) => p.into_inner(), // recover instead of panicking
}; Prevention
- Fix the original panic that poisons the lock; this panic is secondary.
- Wrap effect/update closures in catch_unwind or error boundaries.
- Keep critical sections under write locks small and infallible.
When it happens
Trigger: Calling .or_poisoned() on Result<RwLockReadGuard, PoisonError<...>> — i.e. any .read() on a std::sync::RwLock that was poisoned because a previous lock holder panicked while mutating guarded state.
Common situations: A panic inside a Leptos reactive effect/update closure holding a write lock on shared reactive state; subsequent reads of the same signal/graph node then hit the poisoned lock and panic with "lock poisoned".
Related errors
- failed to read hash file
- Unsupported server function HTTP method: {method:?}
- {}
- Reading from a LocalResource outside Suspense in `ssr` mode
- at {location}, the `sandboxed-arenas` feature is active, but
AI-assisted analysis of leptos-rs/leptos@32d20f6c9d (2026-09-01).
Data as JSON: /api/errors/cd410f7f8ee0fe0b.
Report an issue: GitHub.