nautechsystems/nautilus_trader · error

Failed to extract PyDataActor: {e}

Error message

Failed to extract PyDataActor: {e}

What it means

Raised when the object constructed from the exec algorithm config cannot be extracted as PyRefMut<PyDataActor> — i.e. the instantiated class is not a v2 DataActor-backed Python exec algorithm. The node needs the native actor payload to configure and register it.

Source

Thrown at crates/live/src/python/node.rs:1558

                {
                    if let Some(config_obj) = config_instance.as_ref() {
                        py_exec_algorithm_ref.configure_from_py_config(config_obj)?;
                    }

                    py_exec_algorithm_ref.set_python_instance(&python_exec_algorithm)?;
                    let actor_id = ActorId::new(py_exec_algorithm_ref.exec_algorithm_id().inner());

                    return Ok((
                        python_exec_algorithm.unbind(),
                        Some(py_exec_algorithm_ref.clone()),
                        actor_id,
                    ));
                }

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

                // Extract ID from config: prefer exec_algorithm_id, fall back to actor_id
                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. Ensure the configured class subclasses nautilus_trader.trading.actor.DataActor / the v2 ExecAlgorithm base
  2. Point config_path at the correct class (not a strategy or plain actor)
  3. Rebuild nautilus_trader so the Rust extension matches the installed Python package
  4. Instantiate the class directly in a REPL to check its MRO contains the native base

Example fix

// before
config_path="myalgos.exec:MyPlainActor"  # only subclasses object
// after
class MyExec(ExecAlgorithm): ...
config_path="myalgos.exec:MyExec"
Defensive patterns

Strategy: type-guard

Validate before calling

from nautilus_trader.common.actor import Actor  # and relevant ExecAlgorithm base
obj = import_cls(config_path)
assert any("ExecAlgorithm" in c.__name__ or issubclass(obj, Actor) for c in type(obj).__mro__), "not a v2 actor-based exec algorithm"

Type guard

def is_actor_based(obj) -> bool:
    from nautilus_trader.common.actor import Actor
    return isinstance(obj, Actor)

Try / catch

try:
    node.add_exec_algorithm_from_config(cfg)
except Exception as e:
    if "Failed to extract PyDataActor" in str(e):
        raise TypeError(f"{cfg.config_path} does not instantiate a v2 DataActor/ExecAlgorithm") from e
    raise

Prevention

When it happens

Trigger: add_exec_algorithm_from_config where the imported class instantiates into something that is not a nautilus_trader Actor/ExecAlgorithm (e.g. it subclasses only Actor, is a plain class, or the wrong class was pointed at).

Common situations: Pointing config_path at a Strategy or plain class instead of an ExecAlgorithm/DataActor subclass; custom exec algorithms not migrated to the v2 base classes; instantiating via a factory function returning the wrong type.

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