nautechsystems/nautilus_trader · error

Python on_order failed: {e}

Error message

Python on_order failed: {e}

What it means

DataActor command execution wraps the Python on_order callback; any exception raised inside the user's Python on_order handler is converted into this anyhow error by execute_exec_algorithm_command. It means the exec algorithm's Python-level order-submission handler failed, aborting the SubmitOrder trading command.

Source

Thrown at crates/common/src/python/actor.rs:264

}

#[expect(clippy::needless_pass_by_ref_mut)]
impl PyDataActorInner {
    fn execute_exec_algorithm_command(&mut self, command: &TradingCommand) -> anyhow::Result<()> {
        if self.core.config.log_commands {
            let id = self.core.actor_id;
            log::info!("{id} {RECV}{CMD} {command}");
        }

        if self.core.state() != ComponentState::Running {
            return Ok(());
        }

        match command {
            TradingCommand::SubmitOrder(cmd) => {
                let order = DataActor::cache(self).try_order(&cmd.client_order_id)?;
                self.dispatch_on_order(order)
                    .map_err(|e| anyhow::anyhow!("Python on_order failed: {e}"))
            }
            TradingCommand::SubmitOrderList(cmd) => {
                let orders = self.orders_for_list(&cmd.order_list)?;
                self.dispatch_on_order_list(cmd.order_list.clone(), orders)
                    .map_err(|e| anyhow::anyhow!("Python on_order_list failed: {e}"))
            }
            _ => {
                log::warn!("Unhandled command type: {command}");
                Ok(())
            }
        }
    }

    fn orders_for_list(&self, order_list: &OrderList) -> anyhow::Result<Vec<OrderAny>> {
        let cache = DataActor::cache(self);
        let mut orders = Vec::with_capacity(order_list.client_order_ids.len());

        for client_order_id in &order_list.client_order_ids {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read the chained '{e}' cause to find the underlying Python exception and fix the on_order handler
  2. Guard on_order with checks that the order and its instrument exist in cache before use
  3. Test the exec algorithm with a backtest covering submit-order paths before live use
  4. Log and handle expected edge cases (e.g. denied/canceled orders) inside on_order instead of raising

Example fix

# before
def on_order(self, order):
    instrument = self.cache.instrument(order.instrument_id)
    price = instrument.make_price(self.limit)  # raises if instrument is None
# after
def on_order(self, order):
    instrument = self.cache.instrument(order.instrument_id)
    if instrument is None:
        self.log.error(f"No instrument for {order.instrument_id}")
        return
    price = instrument.make_price(self.limit)
Defensive patterns

Strategy: try-catch

Validate before calling

def check_order_ready(order) -> bool:
    return (
        order is not None
        and self.cache.instrument(order.instrument_id) is not None
        and order.client_order_id is not None
    )

Type guard

def order_in_cache(self, order) -> bool:
    return self.cache.order(order.client_order_id) is not None

Try / catch

def on_order(self, order):
    try:
        self._handle_order(order)
    except Exception as e:
        self.log.exception(f"on_order failed for {order.client_order_id}: {e}")
        # do not re-raise unless the actor must halt

Prevention

When it happens

Trigger: An exec algorithm command TradingCommand::SubmitOrder is executed and the actor's dispatch_on_order invokes the Python on_order override, which raises an exception (bad attribute, missing cache data, invalid order state, Python bug).

Common situations: User-defined on_order in a Python exec algorithm references an attribute not yet initialized, handles orders whose instrument is missing from cache, or throws on None/odd order states during live reconciliation.

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


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