{"record":{"id":"9d3ca40cab830ef7","repo":"influxdata/influxdb","slug":"not-poisoned","errorCode":null,"errorMessage":"not poisoned","messagePattern":"not poisoned","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"core/object_store_mem_cache/src/cache_system/hook/notify/mod.rs","lineNumber":24,"sourceCode":"    },\n    task::{Context, Poll, Waker},\n};\n\nuse futures::Stream;\n\n#[cfg(test)]\npub(crate) mod test_utils;\n\n#[derive(Debug, Default)]\npub(crate) struct Mailbox {\n    counter: AtomicUsize,\n    wakers: Mutex<Vec<Waker>>,\n}\n\nimpl Mailbox {\n    /// Notify all notifiers\n    pub(crate) fn notify(&self) {\n        let mut guard = self.wakers.lock().expect(\"not poisoned\");\n\n        // bump counter AFTER acquiring lock but before notifying wakers\n        self.counter.fetch_add(1, Ordering::SeqCst);\n\n        for waker in guard.drain(..) {\n            waker.wake();\n        }\n    }\n\n    /// Notifier.\n    pub(crate) fn notifier(self: &Arc<Self>) -> Notifier {\n        Notifier {\n            mailbox: Arc::downgrade(self),\n            counter: 0,\n        }\n    }\n}\n","sourceCodeStart":6,"sourceCodeEnd":42,"githubUrl":"https://github.com/influxdata/influxdb/blob/d28e26e048401c53cbb98cf2d6ab0cf1e98048ca/core/object_store_mem_cache/src/cache_system/hook/notify/mod.rs#L6-L42","documentation":"The Mailbox in object_store_mem_cache's cache hooks coordinates task wakers using a Mutex<Vec<Waker>> plus an AtomicUsize counter. notify() locks the waker list and wakes every registered waker while holding the lock; if that code panics (a waker.wake() implementation panicking is the classic cause), the mutex is poisoned and every later lock() in notify()/poll_next() dies on this expect. The 'not poisoned' message is a downstream casualty - the real failure is the earlier panic in your logs.","triggerScenarios":"A registered Waker panics inside wake() while notify() holds the lock (guard is alive across the drain/wake loop); subsequently every call to notify() panics here because the mutex is already poisoned.","commonSituations":"Custom executors or futures with panicking wakers/poll implementations; any panic while holding the mailbox lock in the cache layer; cascading failures after an initial panic elsewhere in the cache hook.","solutions":["Search the logs for the FIRST panic/backtrace - this expect is only a symptom; fix the original panic","Never panic inside wake()/poll implementations registered with this cache (validate waker invariants before use)","Patch defensive recovery: lock().unwrap_or_else(|e| e.into_inner()) - the Vec<Waker> is plain data and safe to keep using","Stress-test the memory-cache layer (high concurrency get/put) to reproduce the original race"],"exampleFix":"// before\nlet mut guard = self.wakers.lock().expect(\"not poisoned\");\n\n// after: recover from poisoning instead of cascading the panic\nlet mut guard = self.wakers.lock().unwrap_or_else(|e| e.into_inner());\n","handlingStrategy":"fallback","validationCode":null,"typeGuard":null,"tryCatchPattern":"// if you maintain this code: recover instead of cascading\nlet mut guard = self.wakers.lock().unwrap_or_else(|poisoned| poisoned.into_inner());\n// Vec<Waker> is plain data; continuing is safe\n","preventionTips":["Never panic inside wake()/poll code registered with the cache hooks","Investigate the FIRST panic in the logs; 'not poisoned' panics are downstream symptoms","Stress-test the memory cache under concurrency to flush out waker races"],"tags":["mutex","poisoning","waker","concurrency","cache","panic","influxdb3"],"backgroundTag":"mutex-poisoned","analyzedSha":"d28e26e048401c53cbb98cf2d6ab0cf1e98048ca","analyzedAt":"2026-08-16T19:53:34.623Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}