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
- Inspect the chained `{e}` for the underlying Python exception raised during attribute lookup and fix the wrapper class.
- Ensure the Python algorithm class is a plain class exposing on_order_list/on_order without a __getattr__ that can raise.
- Verify the PyExecutionAlgorithm holds a live Python object (not a dropped/GC'd reference) before dispatch.
- 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
- Avoid __getattr__ implementations that can raise on the algorithm class.
- Hold the Python object with a stable Py<PyAny> reference for the algorithm's lifetime.
- Pin and test against the pyo3 version used by the bindings.
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
- Failed to convert historical data to Python: unsupported typ
- Failed to convert instrument to Python: {e}
- Failed to convert batched deltas to Python: {e}
- Invalid book_snapshot_output: '{book_snapshot_output}'. Expe
- Python on_pool_swap failed: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/04f048d4fc9ca594.
Report an issue: GitHub.