{"record":{"id":"57792f86679bd96e","repo":"leptos-rs/leptos","slug":"lock-poisoned-57792f","errorCode":null,"errorMessage":"lock poisoned","messagePattern":"lock poisoned","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"tachys/src/reactive_graph/mod.rs","lineNumber":594,"sourceCode":"pub type SharedReactiveFunction<T> = Arc<Mutex<dyn FnMut() -> T + Send>>;\n\n/// A reactive view function.\npub trait ReactiveFunction: Send + 'static {\n    /// The return type of the function.\n    type Output;\n\n    /// Call the function.\n    fn invoke(&mut self) -> Self::Output;\n\n    /// Converts the function into a cloneable, shared type.\n    fn into_shared(self) -> Arc<Mutex<dyn FnMut() -> Self::Output + Send>>;\n}\n\nimpl<T: 'static> ReactiveFunction for Arc<Mutex<dyn FnMut() -> T + Send>> {\n    type Output = T;\n\n    fn invoke(&mut self) -> Self::Output {\n        let mut fun = self.lock().expect(\"lock poisoned\");\n        fun()\n    }\n\n    fn into_shared(self) -> Arc<Mutex<dyn FnMut() -> Self::Output + Send>> {\n        self\n    }\n}\n\nimpl<T: Send + Sync + 'static> ReactiveFunction\n    for Arc<dyn Fn() -> T + Send + Sync>\n{\n    type Output = T;\n\n    fn invoke(&mut self) -> Self::Output {\n        self()\n    }\n\n    fn into_shared(self) -> Arc<Mutex<dyn FnMut() -> Self::Output + Send>> {","sourceCodeStart":576,"sourceCodeEnd":612,"githubUrl":"https://github.com/leptos-rs/leptos/blob/32d20f6c9d517451d77beb68d88c7716823dac41/tachys/src/reactive_graph/mod.rs#L576-L612","documentation":"ReactiveFunction::invoke for Arc<Mutex<dyn FnMut() -> T>> locks the mutex and panics if it is poisoned. Poisoning happens when another thread panicked while holding the lock, leaving the wrapped closure in an inconsistent state; the library chooses to propagate that as a panic rather than silently skip the function.","triggerScenarios":"A closure passed as a reactive function (e.g. as a signal/derived dependency) panicked on some thread while holding the lock; subsequently any invoke() call hits the poisoned mutex.","commonSituations":"A derived/computation closure that indexes out of bounds or unwraps None on one render pass, then the reactive graph re-invokes it later; panics inside event handlers guarded by the same Arc<Mutex<...>>.","solutions":["Fix the underlying panic inside the FnMut closure so the mutex is never poisoned","Wrap the closure body so transient errors return a default T instead of panicking","If a panic is unavoidable/recoverable, catch it at the outer reactive boundary and rebuild the function value","Avoid calling .expect/unwraps inside reactive closures on possibly-invalid data"],"exampleFix":"// before\nlet f = Arc::new(Mutex::new(move || other.signal.get_untracked().unwrap())); // panics -> poison\n// after\nlet f = Arc::new(Mutex::new(move || other.signal.get_untracked().unwrap_or_default()));\n","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Mutex poisoning surfaces at lock(); guard the closure body so it never panics,\n// and catch panics at the reactive boundary:\nlet out = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {\n    fun_clone.get_untracked()\n}));\nif out.is_err() { log::error(\"reactive function panicked; mutex may be poisoned\"); }","preventionTips":["Never unwrap/expect/index-panic inside reactive closures","Return Default/default values for invalid inputs in FnMut closures","Catch panics at task boundaries before they poison shared locks","Consider parking_lot::Mutex (poison-free) for shared reactive state in your own code"],"tags":["reactive","mutex","panic"],"backgroundTag":"lock-poisoned","analyzedSha":"32d20f6c9d517451d77beb68d88c7716823dac41","analyzedAt":"2026-09-01T18:55:42.580Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-09T01:17:15.007Z"}