{"record":{"id":"5ece821930f3899e","repo":"rayon-rs/rayon","slug":"owner-thread","errorCode":null,"errorMessage":"owner thread","messagePattern":"owner thread","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"rayon-core/src/latch.rs","lineNumber":397,"sourceCode":"                },\n            },\n        }\n    }\n\n    #[inline]\n    pub(super) fn increment(&self) {\n        let old_counter = self.counter.fetch_add(1, Ordering::Relaxed);\n        debug_assert!(old_counter != 0);\n    }\n\n    pub(super) fn wait(&self, owner: Option<&WorkerThread>) {\n        match &self.kind {\n            CountLatchKind::Stealing {\n                latch,\n                registry,\n                worker_index,\n            } => unsafe {\n                let owner = owner.expect(\"owner thread\");\n                debug_assert_eq!(registry.id(), owner.registry().id());\n                debug_assert_eq!(*worker_index, owner.index());\n                owner.wait_until(latch);\n            },\n            CountLatchKind::Blocking { latch } => latch.wait(),\n        }\n    }\n}\n\nimpl Latch for CountLatch {\n    #[inline]\n    unsafe fn set(this: *const Self) {\n        unsafe {\n            if (*this).counter.fetch_sub(1, Ordering::SeqCst) == 1 {\n                // NOTE: Once we call `set` on the internal `latch`,\n                // the target may proceed and invalidate `this`!\n                match (*this).kind {\n                    CountLatchKind::Stealing {","sourceCodeStart":379,"sourceCodeEnd":415,"githubUrl":"https://github.com/rayon-rs/rayon/blob/ee0a00bdb1ab039e178a215ad5712fb7fa58e58f/rayon-core/src/latch.rs#L379-L415","documentation":"Assertion failure inside Latch::wait in rayon-core. The wait method takes an Option<&WorkerThread>; when the latch kind is CountLatchKind::Stealing (a stealing-based count latch), waiting requires knowledge of the current worker thread to verify latch ownership and registry identity. The code calls owner.expect(\"owner thread\"), so passing None with a stealing latch panics. It is an internal invariant guard, not user-input validation: callers such as broadcast_in must supply Some(worker_thread) whenever a stealing latch is in use. A None owner reaching this path indicates an API misuse inside the thread pool's synchronization machinery.","triggerScenarios":"Calling `broadcast`/`broadcast_in` outside of a rayon worker thread such that the stealing CountLatch has no `owner` context — e.g. invoking broadcast-based APIs from a non-worker thread where the code path expects an owned worker.","commonSituations":"Calling `ThreadPool::broadcast` from a thread other than expected context, or mixing scopes/broadcast across manually managed threads.","solutions":["Ensure `broadcast`/`broadcast_in` is called from an allowed thread context per its docs (owner thread present)","Use `install(pool, ...)` or run inside the pool's scope so an owner thread is available","Prefer `join`/`scope` APIs which don't require the broadcast latch path","Upgrade rayon-core; guard assertions around latch ownership have evolved"],"exampleFix":"// before\npool.broadcast(|ctx| ...); // from arbitrary thread hitting latch path\n// after\npool.install(|| {\n    pool.broadcast(|ctx| ...);\n});","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"catch_unwind(AssertUnwindSafe(|| pool.broadcast(|ctx| ...)))","preventionTips":["Call broadcast within pool context (install/scope)","Avoid mixing broadcast with manual threads","Keep rayon-core updated"],"tags":["rayon","panic","latch","concurrency"],"backgroundTag":"internal-invariant-violation","analyzedSha":"ee0a00bdb1ab039e178a215ad5712fb7fa58e58f","analyzedAt":"2026-09-07T23:28:47.588Z","contentChangedAt":"2026-09-07T23:28:47.588Z","schemaVersion":2},"datasetVersion":"2026-09-15T23:17:13.987Z"}