nautechsystems/nautilus_trader · error

Failed to extract PyDataActor: {e}

Error message

Failed to extract PyDataActor: {e}

What it means

When adding a Python exec algorithm to the backtest engine, the provided object must be extractable as a PyDataActor (a registered Rust wrapper type for Python actors). PyO3's extract failed, so the object is not a recognized actor/strategy instance.

Source

Thrown at crates/backtest/src/python/engine.rs:963

    ) -> PyResult<()> {
        Self::ensure_can_add_exec_algorithm(engine)?;

        if Self::try_add_py_execution_algorithm(engine, exec_algorithm)? {
            return Ok(());
        }

        let actor_id = Python::attach(|py| -> anyhow::Result<ActorId> {
            let bound = exec_algorithm.bind(py);

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

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

            if let Some(config_obj) = config_instance.as_ref() {
                let id_attr = config_obj
                    .getattr("exec_algorithm_id")
                    .ok()
                    .filter(|v| !v.is_none())
                    .or_else(|| config_obj.getattr("actor_id").ok().filter(|v| !v.is_none()));

                if let Some(id_value) = id_attr {
                    let actor_id_val = if let Ok(eaid) = id_value.extract::<ExecAlgorithmId>() {
                        ActorId::new(eaid.inner())
                    } else if let Ok(aid) = id_value.extract::<ActorId>() {
                        aid
                    } else if let Ok(aid_str) = id_value.extract::<String>() {
                        ActorId::new_checked(&aid_str)?
                    } else {
                        anyhow::bail!("Invalid `exec_algorithm_id`/`actor_id` type");
                    };

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Instantiate the exec algorithm from a class that inherits nautilus_trader.trading.strategy.Strategy (or the actor base) and pass the instance.
  2. Verify you are passing the object, not the class: add_exec_algorithm(MyAlgo(config)), not add_exec_algorithm(MyAlgo).
  3. Check that the nautilus_trader Python package version matches the Rust/PyO3 bindings in use.

Example fix

# before
engine.add_python_exec_algorithm(MyExecAlgo, config)  # class passed
# after
engine.add_python_exec_algorithm(MyExecAlgo(config), config)
Defensive patterns

Strategy: type-guard

Validate before calling

from nautilus_trader.common.actor import Actor
assert isinstance(exec_algorithm, Actor), "exec algorithm must be an Actor/Strategy instance"

Type guard

def is_py_data_actor(obj) -> bool:
    from nautilus_trader.common.actor import Actor
    return isinstance(obj, Actor) and not isinstance(obj, type)

Try / catch

try:
    engine.add_python_exec_algorithm(algo, config)
except Exception as e:
    if "Failed to extract PyDataActor" in str(e):
        raise TypeError(f"{algo!r} is not an Actor instance; pass an instantiated Strategy") from e
    raise

Prevention

When it happens

Trigger: Calling add_python_exec_algorithm with an object that is not an instance of a class deriving from nautilus_trader's Actor/Strategy base (e.g. a plain Python object, a function, or a class instead of an instance).

Common situations: Passing the exec algorithm class instead of an instantiated object; passing an algorithm built on an older/other base class; passing a non-actor callable such as a raw function configured via exec_algorithm.

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/aec108251cd01d79. Report an issue: GitHub.