{"record":{"id":"8ea614d4f270de82","repo":"gitui-org/gitui","slug":"lock-err","errorCode":null,"errorMessage":"lock err","messagePattern":"lock err","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"src/notify_mutex.rs","lineNumber":28,"sourceCode":"}\n\nimpl<T> NotifiableMutex<T>\nwhere\n\tT: Send + Sync,\n{\n\t///\n\tpub fn new(start_value: T) -> Self {\n\t\tSelf {\n\t\t\tdata: Arc::new((Mutex::new(start_value), Condvar::new())),\n\t\t}\n\t}\n\n\t///\n\tpub fn wait(&self, condition: T)\n\twhere\n\t\tT: PartialEq + Copy,\n\t{\n\t\tlet mut data = self.data.0.lock().expect(\"lock err\");\n\t\twhile *data != condition {\n\t\t\tdata = self.data.1.wait(data).expect(\"wait err\");\n\t\t}\n\t\tdrop(data);\n\t}\n\n\t///\n\tpub fn set_and_notify(&self, value: T) {\n\t\t*self.data.0.lock().expect(\"set err\") = value;\n\t\tself.data.1.notify_one();\n\t}\n\n\t///\n\tpub fn get(&self) -> T\n\twhere\n\t\tT: Copy,\n\t{\n\t\t*self.data.0.lock().expect(\"get err\")","sourceCodeStart":10,"sourceCodeEnd":46,"githubUrl":"https://github.com/gitui-org/gitui/blob/2fa693cb6ed431b21ebc300dd02e83c2476699ce/src/notify_mutex.rs#L10-L46","documentation":"Notify<T> wraps a std::sync::Mutex; wait() does lock().expect(\"lock err\"). A std Mutex lock only fails when the mutex is poisoned - some thread panicked while holding it. So this message is always a secondary symptom: the real failure is an earlier panic elsewhere (often one of gitui's render/path panics) that fired while the lock was held.","triggerScenarios":"Any panic in gitui while a worker thread holds the Notify's mutex (e.g. a status-tree or get-status panic between set_and_notify calls), followed by another thread calling wait().","commonSituations":"Shutdown races after a primary panic; flaky worker threads in older gitui versions; concurrency bugs introduced by local modifications.","solutions":["Look UP the log (cache gitui.log) or terminal scrollback for the first panic - fix or report that one; 'lock err' is never the root cause.","Update gitui - thread and panic handling improved across releases.","If embedding a notify-mutex of this shape, recover with lock().unwrap_or_else(|e| e.into_inner()) or use parking_lot, whose mutexes do not poison."],"exampleFix":"// before\nlet mut data = self.data.0.lock().expect(\"lock err\");\n// after: tolerate poisoning, keep the (consistent-enough) inner value\nlet mut data = self.data.0.lock().unwrap_or_else(|poisoned| poisoned.into_inner());","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"// std-only recovery from a poisoned lock\nlet guard = match m.lock() {\n    Ok(g) => g,\n    Err(poisoned) => poisoned.into_inner(), // fall back to the inner value\n};","preventionTips":["Never panic while holding a shared mutex - move fallible work outside the critical section.","Use parking_lot::Mutex (no poisoning) for notify-style primitives.","Read the earlier panic in the log - 'lock err' is never the root cause."],"tags":["mutex","poisoning","panic","concurrency","secondary"],"backgroundTag":"mutex-poisoned","analyzedSha":"2fa693cb6ed431b21ebc300dd02e83c2476699ce","analyzedAt":"2026-08-16T23:07:36.562Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}