nautechsystems/nautilus_trader · error

Failed to convert InstrumentAny to Python: {e}

Error message

Failed to convert InstrumentAny to Python: {e}

What it means

Converting an `InstrumentAny` (a Rust enum of instrument definitions) into a Python object failed inside `on_instrument`, before the Python callback was even invoked. `instrument_any_to_pyobject` maps each instrument variant to its pyo3-exposed Python type; a conversion error (unsupported variant or an inner conversion failure) is wrapped at strategy.rs:1137 as `Failed to convert InstrumentAny to Python: {e}`.

Source

Thrown at crates/trading/src/python/strategy.rs:1137

    fn on_signal(&mut self, signal: &Signal) -> anyhow::Result<()> {
        self.dispatch_on_signal(signal)
            .map_err(|e| anyhow::anyhow!("Python on_signal failed: {e}"))
    }

    fn on_queue_state(&mut self, event: &QueueStateChanged) -> anyhow::Result<()> {
        self.dispatch_on_queue_state(event)
            .map_err(|e| anyhow::anyhow!("Python on_queue_state failed: {e}"))
    }

    fn on_socket_state(&mut self, event: &SocketStateChanged) -> anyhow::Result<()> {
        self.dispatch_on_socket_state(event)
            .map_err(|e| anyhow::anyhow!("Python on_socket_state failed: {e}"))
    }

    fn on_instrument(&mut self, instrument: &InstrumentAny) -> anyhow::Result<()> {
        Python::attach(|py| {
            let py_instrument = instrument_any_to_pyobject(py, instrument.clone())
                .map_err(|e| anyhow::anyhow!("Failed to convert InstrumentAny to Python: {e}"))?;
            self.dispatch_on_instrument(py_instrument)
                .map_err(|e| anyhow::anyhow!("Python on_instrument failed: {e}"))
        })
    }

    fn on_quote(&mut self, quote: &QuoteTick) -> anyhow::Result<()> {
        self.dispatch_on_quote(*quote)
            .map_err(|e| anyhow::anyhow!("Python on_quote failed: {e}"))
    }

    fn on_trade(&mut self, tick: &TradeTick) -> anyhow::Result<()> {
        self.dispatch_on_trade(*tick)
            .map_err(|e| anyhow::anyhow!("Python on_trade failed: {e}"))
    }

    fn on_bar(&mut self, bar: &Bar) -> anyhow::Result<()> {
        self.dispatch_on_bar(*bar)
            .map_err(|e| anyhow::anyhow!("Python on_bar failed: {e}"))

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Read `{e}` to see which instrument type/field failed conversion.
  2. Upgrade the Python package and core to matching versions so the instrument variant has a Python binding.
  3. Filter or skip the offending instrument type in your subscription/universe selection until support exists.
  4. If persistent, report/patch `instrument_any_to_pyobject` to cover the missing variant.

Example fix

// before (subscribing to every instrument in the venue)
for inst in venue.instruments:
    self.subscribe_instrument(inst)

// after
from nautilus_trader.model.instruments import Instrument  # ensure bindings exist
for inst in venue.instruments:
    if isinstance(inst, SUPPORTED_INSTRUMENT_TYPES):
        self.subscribe_instrument(inst)
    else:
        self.log.warning(f"skipping unsupported instrument type: {type(inst)}")
Defensive patterns

Strategy: type-guard

Validate before calling

from nautilus_trader.model.instruments import (
    Equity, ForexPair, CryptoPerpetual, FuturesContract, OptionsContract,
)
SUPPORTED = (Equity, ForexPair, CryptoPerpetual, FuturesContract, OptionsContract)
def convertible(instrument):
    return isinstance(instrument, SUPPORTED)

Type guard

def is_python_convertible(instrument) -> bool:
    return isinstance(instrument, SUPPORTED_INSTRUMENT_TYPES)

Try / catch

try:
    self.subscribe_instrument(inst)
except Exception as e:
    self.log.warning(f"instrument {inst.id} not convertible to Python, skipping: {e}")

Prevention

When it happens

Trigger: An instrument definition event is delivered to the strategy's `on_instrument`; the variant cannot be converted, typically when a new/less-common instrument type (or an instrument carrying fields the Python bindings don't yet support) flows through, or a downstream pyo3 conversion of a field errors.

Common situations: Subscribing to instruments from an adapter that yields an instrument kind whose Python wrapper is missing in the installed version; version mismatch between core crates and the Python package; exotic instrument definitions (unusual option/Spread types) not covered by the conversion.

Understand the failure class

Background: "is not a compatible type" / "cannot merge" errors: when a value's type doesn't match what the library requires — this error's family across 65 libraries.

Related errors


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