nautechsystems/nautilus_trader · error · anyhow::Error
Cannot send order event: sender not initialized
Error message
Cannot send order event: sender not initialized
What it means
ExecutionEmitter lazily holds an Option-like sender (`self.sender.load()`), which is only populated once the emitter is started/initialized. This error is raised by try_send_order_event when that sender slot is still None, so an order event cannot be routed to the execution event stream. It signals a lifecycle bug: the emitter is being used before initialization.
Source
Thrown at crates/live/src/execution/emitter.rs:441
}
/// Emits an order event.
pub fn send_order_event(&self, event: OrderEventAny) {
if let Err(e) = self.try_send_order_event(event) {
log::warn!("{e}");
}
}
/// Emits an order event and returns any channel error to the caller.
///
/// # Errors
///
/// Returns an error if the sender is uninitialized or its receiver is closed.
pub fn try_send_order_event(&self, event: OrderEventAny) -> anyhow::Result<()> {
let sender = self.sender.load();
let sender = sender
.as_ref()
.ok_or_else(|| anyhow::anyhow!("Cannot send order event: sender not initialized"))?;
sender
.send(ExecutionEvent::Order(event))
.map_err(|e| anyhow::anyhow!("Failed to send order event: {e}"))
}
/// Emits a batch of order submitted events as a single channel message.
pub fn send_order_submitted_batch(&self, batch: OrderSubmittedBatch) {
let sender = self.sender.load();
if let Some(sender) = sender.as_ref() {
if let Err(e) = sender.send(ExecutionEvent::OrderSubmittedBatch(batch)) {
log::warn!("Failed to send order submitted batch: {e}");
}
} else {
log::warn!("Cannot send order submitted batch: sender not initialized");
}
}
/// Emits a batch of order accepted events as a single channel message.View on GitHub (pinned to 18893faf8b)
Solutions
- Ensure the ExecutionEmitter is initialized (its `initialize`/start path has run) before emitting any order events.
- Check startup ordering so that reconnect recovery (commit_post_reconnect_mass_status) runs only after the execution engine and emitter are fully wired.
- Guard calls with a readiness check on the emitter and log/skip or queue events until initialized.
- If this occurs unexpectedly, report/inspect: the sender should always be set once the live node is running.
Example fix
// before
emitter.send_order_event(event); // panics-ish error if not initialized
// after
if emitter.is_initialized() {
if let Err(e) = emitter.try_send_order_event(event) { log::error!("{e}"); }
} else {
log::warn!("emitter not initialized; dropping/deferring order event");
} Defensive patterns
Strategy: try-catch
Validate before calling
if !emitter.is_initialized() { log::warn!("emitter not ready"); return; } Type guard
fn emitter_ready(emitter: &ExecutionEmitter) -> bool { emitter.is_initialized() } Try / catch
match emitter.try_send_order_event(event) { Err(e) if e.to_string().contains("sender not initialized") => log::warn!("emitter not initialized: {e}"), Err(e) => log::error!("order event send failed: {e}"), Ok(()) => {} } Prevention
- Always start the live execution engine before any adapter emits events
- Gate reconnect/recovery handlers on engine readiness
- Add startup-order integration tests for adapters
When it happens
Trigger: Calling try_send_order_event (directly or via send_order_event, send_reverted_order, commit_post_reconnect_mass_status, or complete_finalized_swap) before the emitter's sender has been initialized (e.g. before the execution engine/manager start sequence wires the channel).
Common situations: Bots that replay or reconcile orders immediately after connecting to a venue but before the live execution engine finishes startup; reconnect/recovery paths (mass status commit, swap finalization) racing the emitter initialization; custom adapters invoking the emitter out of order.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- std::mem::take(&mut self.shutdown_errors).join("; ")
- Failed to start Coinbase task generation: {e}
- Failed to send order event: {e}
- Cannot send account state: sender not initialized
- Cannot send execution report: sender not initialized
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/9c5a82fed8b87e6a.
Report an issue: GitHub.