nautechsystems/nautilus_trader · error

Python override lookup failed: {e}

Error message

Python override lookup failed: {e}

What it means

Before dispatching `on_order_list`, PyExecutionAlgorithm checks whether the Python object overrides the method using `has_python_override`. If that reflective lookup itself fails (an exception crossing the PyO3 boundary, e.g. calling into Python raised), it is re-wrapped with this message. This is distinct from the callback failing: the lookup of whether the callback exists failed.

Source

Thrown at crates/trading/src/python/algorithm.rs:403

    fn exec_algorithm_core_mut(&mut self) -> &mut ExecutionAlgorithmCore {
        &mut self.inner_mut().core
    }
}

impl ExecutionAlgorithm for PyExecutionAlgorithm {
    fn on_order(&mut self, order: OrderAny) -> anyhow::Result<()> {
        self.dispatch_on_order(order)
            .map_err(|e| anyhow::anyhow!("Python on_order failed: {e}"))
    }

    fn on_order_list(
        &mut self,
        order_list: OrderList,
        orders: Vec<OrderAny>,
    ) -> anyhow::Result<()> {
        if self
            .has_python_override("on_order_list")
            .map_err(|e| anyhow::anyhow!("Python override lookup failed: {e}"))?
        {
            return self
                .dispatch_on_order_list(order_list, orders)
                .map_err(|e| anyhow::anyhow!("Python on_order_list failed: {e}"));
        }

        for order in orders {
            self.on_order(order)?;
        }
        Ok(())
    }

    fn on_start(&mut self) -> anyhow::Result<()> {
        log::info!("Starting {}", self.exec_algorithm_id());
        Ok(())
    }

    fn on_stop(&mut self) -> anyhow::Result<()> {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the chained `{e}` for the underlying Python exception raised during attribute lookup and fix the wrapper class.
  2. Ensure the Python algorithm class is a plain class exposing on_order_list/on_order without a __getattr__ that can raise.
  3. Verify the PyExecutionAlgorithm holds a live Python object (not a dropped/GC'd reference) before dispatch.
  4. Update/align the pyo3 binding version if introspection APIs changed.
Defensive patterns

Strategy: try-catch

Validate before calling

# Python: ensure the class is introspectable (no raising __getattr__)
assert hasattr(type(algo), "on_order_list") or hasattr(algo, "on_order_list")

Try / catch

match algo.on_order_list(order_list, orders) {
    Ok(()) => {},
    Err(e) => log::error!("on_order_list dispatch failed: {e:#}"),
}

Prevention

When it happens

Trigger: Calling on_order_list when `has_python_override("on_order_list")` returns Err — e.g. the wrapped Python object is in a bad state, its class introspection fails, or the Python runtime raised during attribute access.

Common situations: A broken proxy/wrapper class that raises in __getattr__; PyO3 conversion errors when inspecting the instance; interpreter shutdown/initialization issues during attribute lookup.

Related errors


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