nautechsystems/nautilus_trader · error
System command sender should be initialized by runner
Error message
System command sender should be initialized by runner
What it means
`get_system_command_sender` clones the thread-local tokio mpsc sender for SystemCommand. It panics via `.expect` if the runner (`initialize_runner`/node startup) has not installed the sender in this thread's SYSTEM_COMMAND_SENDER slot yet. The library requires the live runner to initialize this state before any other code retrieves the sender.
Source
Thrown at crates/common/src/live/runner.rs:128
/// Replaces the system event sender for the current thread.
pub fn replace_system_event_sender(sender: tokio::sync::mpsc::UnboundedSender<SystemEvent>) {
SYSTEM_EVENT_SENDER.with(|s| {
*s.borrow_mut() = Some(sender);
});
}
/// Gets the thread-local system command sender.
///
/// # Panics
///
/// Panics if the sender is uninitialized.
#[must_use]
pub fn get_system_command_sender() -> tokio::sync::mpsc::UnboundedSender<SystemCommand> {
SYSTEM_COMMAND_SENDER.with(|sender| {
sender
.borrow()
.as_ref()
.expect("System command sender should be initialized by runner")
.clone()
})
}
/// Attempts to get the thread-local system command sender without panicking.
///
/// Returns `None` if the sender is not initialized.
#[must_use]
pub fn try_get_system_command_sender() -> Option<tokio::sync::mpsc::UnboundedSender<SystemCommand>>
{
SYSTEM_COMMAND_SENDER.with(|sender| sender.borrow().as_ref().cloned())
}
/// Sets the thread-local system command sender.
///
/// Can only be called once per thread.
///
/// # PanicsView on GitHub (pinned to 18893faf8b)
Solutions
- Initialize the runner before any call that reaches `get_system_command_sender` (bind senders via the runner startup path)
- In tests, call the test/setup helper that binds a sender (as the failing tests must) before invoking the function under test
- Ensure the call runs on the same OS thread that initialized the runner, since the sender is thread-local
- If you need a non-panicking path, use the documented non-panicking variant that returns Option
Example fix
// before let sender = get_system_command_sender(); // after initialize_senders(); // or start the runner first let sender = get_system_command_sender();
Defensive patterns
Strategy: validation
Validate before calling
if !runner_senders_initialized() {
eprintln!("runner must initialize system command sender first");
return;
}
let sender = get_system_command_sender(); Type guard
fn sender_ready() -> bool {
try_system_command_sender().is_some()
} Try / catch
// Rust panics are not catchable via Result; guard with the non-panicking getter
if let Some(sender) = try_get_system_command_sender() { /* use sender */ } else { init_runner(); } Prevention
- Always start the live runner before touching client APIs that send system commands
- Use the non-panicking try_get variant when initialization order is uncertain
- Keep sender usage on the same OS thread that initialized the runner
- In tests, bind a channel via the runner test helpers before calling the function
When it happens
Trigger: Calling `get_system_command_sender()` from a thread that never ran the runner's sender-binding code, or calling it before `start()` on the runner; tests that exercise helpers which fetch the sender without first calling `bind_system_command_sender`/runner startup.
Common situations: Unit tests invoking public APIs that internally fetch the sender; custom entrypoints bypassing `LiveNode` startup; spawning the call on a different OS thread than the one that initialized the runner.
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
- Execution event sender should be initialized by runner
- task slot is already occupied
- Data event sender should be initialized by runner
- System event sender should be initialized by runner
- registered callback lease was not acquired
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/f819d69769785426.
Report an issue: GitHub.