{"record":{"id":"cd410f7f8ee0fe0b","repo":"leptos-rs/leptos","slug":"lock-poisoned","errorCode":null,"errorMessage":"lock poisoned","messagePattern":"lock poisoned","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"or_poisoned/src/lib.rs","lineNumber":44,"sourceCode":"pub trait OrPoisoned {\n    /// The inner guard type.\n    type Inner;\n\n    /// Unwraps the lock.\n    ///\n    /// ## Panics\n    ///\n    /// Will panic if the lock is poisoned.\n    fn or_poisoned(self) -> Self::Inner;\n}\n\nimpl<'a, T: ?Sized> OrPoisoned\n    for Result<RwLockReadGuard<'a, T>, PoisonError<RwLockReadGuard<'a, T>>>\n{\n    type Inner = RwLockReadGuard<'a, T>;\n\n    fn or_poisoned(self) -> Self::Inner {\n        self.expect(\"lock poisoned\")\n    }\n}\n\nimpl<'a, T: ?Sized> OrPoisoned\n    for Result<RwLockWriteGuard<'a, T>, PoisonError<RwLockWriteGuard<'a, T>>>\n{\n    type Inner = RwLockWriteGuard<'a, T>;\n\n    fn or_poisoned(self) -> Self::Inner {\n        self.expect(\"lock poisoned\")\n    }\n}\n\nimpl<'a, T: ?Sized> OrPoisoned for LockResult<MutexGuard<'a, T>> {\n    type Inner = MutexGuard<'a, T>;\n\n    fn or_poisoned(self) -> Self::Inner {\n        self.expect(\"lock poisoned\")","sourceCodeStart":26,"sourceCodeEnd":62,"githubUrl":"https://github.com/leptos-rs/leptos/blob/32d20f6c9d517451d77beb68d88c7716823dac41/or_poisoned/src/lib.rs#L26-L62","documentation":"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.","triggerScenarios":"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.","commonSituations":"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\".","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)."],"exampleFix":"// before\nlet guard = lock.write().or_poisoned();\n\n// after\nlet guard = match lock.write() {\n    Ok(g) => g,\n    Err(poisoned) => poisoned.into_inner(), // recover data despite poison\n};","handlingStrategy":"try-catch","validationCode":"if lock.is_poisoned() {\n    // recover or restart before reading\n}","typeGuard":"fn lock_healthy<T>(lock: &RwLock<T>) -> bool {\n    !lock.is_poisoned()\n}","tryCatchPattern":"let guard = match lock.read() {\n    Ok(g) => g,\n    Err(p) => p.into_inner(), // recover instead of panicking\n};","preventionTips":["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."],"tags":["rust","concurrency","rwlock","poisoning","leptos"],"backgroundTag":"lock-poisoned","analyzedSha":"32d20f6c9d517451d77beb68d88c7716823dac41","analyzedAt":"2026-09-01T18:55:42.580Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T01:17:15.007Z"}