{"record":{"id":"f819d69769785426","repo":"nautechsystems/nautilus_trader","slug":"system-command-sender-should-be-initialized-by-run","errorCode":null,"errorMessage":"System command sender should be initialized by runner","messagePattern":"System command sender should be initialized by runner","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/common/src/live/runner.rs","lineNumber":128,"sourceCode":"/// Replaces the system event sender for the current thread.\npub fn replace_system_event_sender(sender: tokio::sync::mpsc::UnboundedSender<SystemEvent>) {\n    SYSTEM_EVENT_SENDER.with(|s| {\n        *s.borrow_mut() = Some(sender);\n    });\n}\n\n/// Gets the thread-local system command sender.\n///\n/// # Panics\n///\n/// Panics if the sender is uninitialized.\n#[must_use]\npub fn get_system_command_sender() -> tokio::sync::mpsc::UnboundedSender<SystemCommand> {\n    SYSTEM_COMMAND_SENDER.with(|sender| {\n        sender\n            .borrow()\n            .as_ref()\n            .expect(\"System command sender should be initialized by runner\")\n            .clone()\n    })\n}\n\n/// Attempts to get the thread-local system command sender without panicking.\n///\n/// Returns `None` if the sender is not initialized.\n#[must_use]\npub fn try_get_system_command_sender() -> Option<tokio::sync::mpsc::UnboundedSender<SystemCommand>>\n{\n    SYSTEM_COMMAND_SENDER.with(|sender| sender.borrow().as_ref().cloned())\n}\n\n/// Sets the thread-local system command sender.\n///\n/// Can only be called once per thread.\n///\n/// # Panics","sourceCodeStart":110,"sourceCodeEnd":146,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/common/src/live/runner.rs#L110-L146","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nlet sender = get_system_command_sender();\n// after\ninitialize_senders(); // or start the runner first\nlet sender = get_system_command_sender();","handlingStrategy":"validation","validationCode":"if !runner_senders_initialized() {\n    eprintln!(\"runner must initialize system command sender first\");\n    return;\n}\nlet sender = get_system_command_sender();","typeGuard":"fn sender_ready() -> bool {\n    try_system_command_sender().is_some()\n}","tryCatchPattern":"// Rust panics are not catchable via Result; guard with the non-panicking getter\nif let Some(sender) = try_get_system_command_sender() { /* use sender */ } else { init_runner(); }","preventionTips":["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"],"tags":["rust","panic","thread-local","async","runner"],"backgroundTag":"internal-invariant-violation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}