nautechsystems/nautilus_trader · error

Failed to extract PyStrategy: {e}

Error message

Failed to extract PyStrategy: {e}

What it means

`prepare_python_strategy_instance` extracts the supplied Python strategy object into `PyRefMut<PyStrategy>` to configure it. PyO3 extraction fails unless the object's class inherits from the Rust-backed `PyStrategy` base (`nautilus_trader.trading.strategy.Strategy`), producing this error.

Source

Thrown at crates/system/src/python/registration.rs:214

        self.validate_actor_or_strategy_registration()?;

        let existing_order_id_tags: Vec<&str> =
            self.strategy_ids.iter().map(StrategyId::get_tag).collect();

        let strategy_id = Python::attach(|py| -> anyhow::Result<StrategyId> {
            let bound = strategy.bind(py);

            let config_instance = bound
                .getattr("config")
                .ok()
                .filter(|config| !config.is_none());

            let class_name = bound.get_type().name()?.to_string();

            let mut py_strategy_ref = bound
                .extract::<PyRefMut<PyStrategy>>()
                .map_err(Into::<PyErr>::into)
                .map_err(|e| anyhow::anyhow!("Failed to extract PyStrategy: {e}"))?;

            if let Some(config_obj) = config_instance.as_ref() {
                configure_py_strategy(&mut py_strategy_ref, config_obj)?;
            }

            // Mirrors the native path: a configured ID is kept, otherwise the runtime class name
            // takes the configured order ID tag, or the next positional tag
            let runtime_order_id_tag = py_strategy_ref.order_id_tag();
            let strategy_id = if let Some(strategy_id) = py_strategy_ref.configured_strategy_id() {
                strategy_id
            } else {
                let order_id_tag = normalize_order_id_tag(runtime_order_id_tag.as_deref())
                    .map_or_else(
                        || format!("{:03}", existing_order_id_tags.len()),
                        str::to_string,
                    );
                StrategyId::new_checked(format!("{class_name}-{order_id_tag}"))?
            };

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Make the strategy class inherit from `nautilus_trader.trading.strategy.Strategy`.
  2. Pass the instantiated strategy object (not the class or config) to the add-strategy API.
  3. Confirm the strategy and nautilus_trader Rust core come from the same installed version.

Example fix

// before
class MyStrategy:
    def on_start(self): ...

// after
from nautilus_trader.trading.strategy import Strategy

class MyStrategy(Strategy):
    def on_start(self): ...
Defensive patterns

Strategy: type-guard

Validate before calling

from nautilus_trader.trading.strategy import Strategy
assert isinstance(my_strategy, Strategy), "strategy must subclass Strategy"

Type guard

def is_strategy(obj) -> bool:
    from nautilus_trader.trading.strategy import Strategy
    return isinstance(obj, Strategy)

Try / catch

try:
    trader.add_strategy(strategy)
except Exception as e:
    if "Failed to extract PyStrategy" in str(e):
        raise TypeError(f"{type(strategy).__name__} must subclass nautilus_trader Strategy") from e
    raise

Prevention

When it happens

Trigger: Calling `add_python_strategy_instance` (via trader add_strategy) with a Python object that does not subclass `Strategy` — e.g. a plain class with the right method names, a config, or an object of an incompatible strategy base.

Common situations: Custom strategy forgetting to inherit `nautilus_trader.trading.strategy.Strategy`; passing a StrategyConfig instead of the strategy instance; mixing strategy classes from different nautilus_trader versions.

Understand the failure class

Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.

Related errors


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