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

  1. Ensure the ExecutionEmitter is initialized (its `initialize`/start path has run) before emitting any order events.
  2. Check startup ordering so that reconnect recovery (commit_post_reconnect_mass_status) runs only after the execution engine and emitter are fully wired.
  3. Guard calls with a readiness check on the emitter and log/skip or queue events until initialized.
  4. 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

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/9c5a82fed8b87e6a. Report an issue: GitHub.