nautechsystems/nautilus_trader · error

Failed to downcast to PyDataActor: {e}

Error message

Failed to downcast to PyDataActor: {e}

What it means

This error is raised when a Python object passed as an actor cannot be cast to the `PyDataActor` trait object during registration into global registries. It means the object does not actually implement the PyDataActor interface expected by the system, so `register_in_global_registries()` cannot proceed.

Source

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

            py_data_actor_ref
                .register(trader_id, clock, cache)
                .map_err(|e| anyhow::anyhow!("Failed to register PyDataActor: {e}"))?;

            log::debug!(
                "Internal PyDataActor registered: {}, state: {:?}",
                py_data_actor_ref.is_registered(),
                py_data_actor_ref.state()
            );

            Ok(())
        })?;

        Python::attach(|py| -> anyhow::Result<()> {
            let py_actor = actor.bind(py);
            let py_data_actor_ref = py_actor
                .cast::<PyDataActor>()
                .map_err(|e| anyhow::anyhow!("Failed to downcast to PyDataActor: {e}"))?;
            py_data_actor_ref.borrow().register_in_global_registries()?;
            Ok(())
        })
    }

    /// Rejects a component ID this trader already tracks, whatever kind registered it.
    ///
    /// Duplicate adds are otherwise checked only within a kind, so an actor sharing an ID with a
    /// live strategy would overwrite that strategy's clock, registry entries, and wrapper, and a
    /// rollback would then remove state the attempt did not create. The lifecycle collections are
    /// checked alongside the clocks because a component registered externally and tracked through
    /// `add_*_id_for_lifecycle` has no trader-owned clock.
    fn ensure_component_id_available(&self, component_id: ComponentId) -> anyhow::Result<()> {
        let id = component_id.inner();
        let tracked = self.clocks.contains_key(&component_id)
            || self.actor_ids.iter().any(|actor_id| actor_id.inner() == id)
            || self
                .strategy_ids

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Make the Python class inherit from `nautilus_trader.common.actor.Actor` (or the appropriate Actor subclass)
  2. Check you are passing an actor instance, not a class or a strategy
  3. Verify your nautilus_trader Python package version matches the Rust core version
  4. Inspect the chained `{e}` PyO3 downcast error for the exact type mismatch

Example fix

// before
class MyActor:  # not an Actor
    ...
// after
from nautilus_trader.common.actor import Actor
class MyActor(Actor):
    ...
Defensive patterns

Strategy: type-guard

Validate before calling

from nautilus_trader.common.actor import Actor
assert isinstance(obj, Actor), f"{type(obj)} is not an Actor"

Type guard

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

Try / catch

try:
    trader.add_data_actor(obj)
except Exception as e:
    if "downcast" in str(e):
        raise TypeError(f"{obj!r} must subclass Actor") from e
    raise

Prevention

When it happens

Trigger: Calling `register_python_data_actor` (via trader/actor registration APIs) with a Python object that does not inherit from/implement the NautilusTrader `Actor` Python base (PyDataActor). PyO3's `cast::<PyDataActor>()` fails because the object lacks the Rust-side trait implementation exposed to Python.

Common situations: Passing a plain Python class, a Strategy, or a custom object where an Actor is expected; forgetting to subclass `nautilus_trader.common.actor.Actor`; mixing API versions where the base class changed.

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