nautechsystems/nautilus_trader · error
Data event sender should be initialized by runner
Error message
Data event sender should be initialized by runner
What it means
This panic comes from `get_data_event_sender()` in crates/common/src/live/runner.rs. The function reads a thread-local `DATA_EVENT_SENDER` slot that the live runner must initialize before any consumer fetches it; if the slot is still empty, the expect panics with this message. It exists so components on the live thread can obtain a channel sender for DataEvents without threading it through every constructor.
Source
Thrown at crates/common/src/live/runner.rs:35
//!
//! This module provides thread-local storage for tokio mpsc channels used in live trading.
use std::cell::RefCell;
use crate::messages::{DataEvent, ExecutionEvent, SystemCommand, SystemEvent};
/// Gets the thread-local data event sender.
///
/// # Panics
///
/// Panics if the sender is uninitialized.
#[must_use]
pub fn get_data_event_sender() -> tokio::sync::mpsc::UnboundedSender<DataEvent> {
DATA_EVENT_SENDER.with(|sender| {
sender
.borrow()
.as_ref()
.expect("Data event sender should be initialized by runner")
.clone()
})
}
/// Attempts to get the thread-local data event sender without panicking.
///
/// Returns `None` if the sender is not initialized (e.g., in Python/v1 bridge environments
/// before a runner or adapter bridge has registered a sender).
#[must_use]
pub fn try_get_data_event_sender() -> Option<tokio::sync::mpsc::UnboundedSender<DataEvent>> {
DATA_EVENT_SENDER.with(|sender| sender.borrow().as_ref().cloned())
}
/// Sets the thread-local data event sender.
///
/// Can only be called once per thread.
///
/// # PanicsView on GitHub (pinned to 18893faf8b)
Solutions
- Ensure the live runner initializes the sender on the same thread before components call this function
- Call this only from the runner's thread (it is thread-local); use `try_get_data_event_sender()` (the non-panicking variant) when unsure and handle None
- Restructure initialization so senders are passed explicitly to components instead of fetched from thread-local state
- In tests, initialize the thread-local sender via the runner harness before calling
Example fix
// before
let sender = get_data_event_sender(); // panics on uninitialized thread
// after
let sender = match try_get_data_event_sender() {
Some(s) => s,
None => anyhow::bail!("data event sender not initialized; call from the live runner thread after initialization"),
}; Defensive patterns
Strategy: fallback
Validate before calling
assert!(try_get_data_event_sender().is_some(), "call from live runner thread after init");
Type guard
fn sender_ready() -> bool { try_get_data_event_sender().is_some() } Try / catch
// no exception to catch in Rust; use the non-panicking variant
let sender = try_get_data_event_sender().ok_or_else(|| anyhow!("data event sender not initialized"))?; Prevention
- Call sender accessors only on the runner-initialized thread
- Prefer try_get_* variants at library boundaries
- Initialize runner channels before spawning components
When it happens
Trigger: Calling `get_data_event_sender()` on a thread where the live runner never ran its initialization (i.e. `DATA_EVENT_SENDER` was never set) — e.g. calling from a different thread than the runner's, calling before `run`/`connect` initializes it, or in unit tests without the runner harness.
Common situations: Spawning actor/strategy code on a fresh tokio task or OS thread separate from the runner thread and then grabbing the sender; constructing components in tests without using the runner's initialization path; early startup ordering where a component fetches the sender before the runner sets it.
Understand the failure class
Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.
Related errors
- System event sender should be initialized by runner
- System command sender should be initialized by runner
- Execution event sender should be initialized by runner
- Strategy not registered: OrderFactory not initialized
- in-flight mutex poisoned
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/e8f8766182a7c25f.
Report an issue: GitHub.