rayon-rs/rayon · error
owner thread
Error message
owner thread
What it means
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.
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
Example fix
// before
pool.broadcast(|ctx| ...); // from arbitrary thread hitting latch path
// after
pool.install(|| {
pool.broadcast(|ctx| ...);
}); Defensive patterns
Strategy: try-catch
Try / catch
catch_unwind(AssertUnwindSafe(|| pool.broadcast(|ctx| ...)))
Prevention
- Call broadcast within pool context (install/scope)
- Avoid mixing broadcast with manual threads
- Keep rayon-core updated
When it happens
Trigger: 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.
Common situations: Calling `ThreadPool::broadcast` from a thread other than expected context, or mixing scopes/broadcast across manually managed threads.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- FIFO is empty
- range start should be <= length
- range end should be <= length
- range start should be <= range end
- The global thread pool has not been initialized.
AI-assisted analysis of rayon-rs/rayon@ee0a00bdb1 (2026-09-07).
Data as JSON: /api/errors/5ece821930f3899e.
Report an issue: GitHub.
Appendix: source
Thrown at rayon-core/src/latch.rs:397
},
},
}
}
#[inline]
pub(super) fn increment(&self) {
let old_counter = self.counter.fetch_add(1, Ordering::Relaxed);
debug_assert!(old_counter != 0);
}
pub(super) fn wait(&self, owner: Option<&WorkerThread>) {
match &self.kind {
CountLatchKind::Stealing {
latch,
registry,
worker_index,
} => unsafe {
let owner = owner.expect("owner thread");
debug_assert_eq!(registry.id(), owner.registry().id());
debug_assert_eq!(*worker_index, owner.index());
owner.wait_until(latch);
},
CountLatchKind::Blocking { latch } => latch.wait(),
}
}
}
impl Latch for CountLatch {
#[inline]
unsafe fn set(this: *const Self) {
unsafe {
if (*this).counter.fetch_sub(1, Ordering::SeqCst) == 1 {
// NOTE: Once we call `set` on the internal `latch`,
// the target may proceed and invalidate `this`!
match (*this).kind {
CountLatchKind::Stealing {View on GitHub (pinned to ee0a00bdb1)