{"record":{"id":"2cf1d7de739e579a","repo":"nautechsystems/nautilus_trader","slug":"failed-to-downcast-to-pydataactor-e","errorCode":null,"errorMessage":"Failed to downcast to PyDataActor: {e}","messagePattern":"Failed to downcast to PyDataActor: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/system/src/python/registration.rs","lineNumber":449,"sourceCode":"\n            py_data_actor_ref\n                .register(trader_id, clock, cache)\n                .map_err(|e| anyhow::anyhow!(\"Failed to register PyDataActor: {e}\"))?;\n\n            log::debug!(\n                \"Internal PyDataActor registered: {}, state: {:?}\",\n                py_data_actor_ref.is_registered(),\n                py_data_actor_ref.state()\n            );\n\n            Ok(())\n        })?;\n\n        Python::attach(|py| -> anyhow::Result<()> {\n            let py_actor = actor.bind(py);\n            let py_data_actor_ref = py_actor\n                .cast::<PyDataActor>()\n                .map_err(|e| anyhow::anyhow!(\"Failed to downcast to PyDataActor: {e}\"))?;\n            py_data_actor_ref.borrow().register_in_global_registries()?;\n            Ok(())\n        })\n    }\n\n    /// Rejects a component ID this trader already tracks, whatever kind registered it.\n    ///\n    /// Duplicate adds are otherwise checked only within a kind, so an actor sharing an ID with a\n    /// live strategy would overwrite that strategy's clock, registry entries, and wrapper, and a\n    /// rollback would then remove state the attempt did not create. The lifecycle collections are\n    /// checked alongside the clocks because a component registered externally and tracked through\n    /// `add_*_id_for_lifecycle` has no trader-owned clock.\n    fn ensure_component_id_available(&self, component_id: ComponentId) -> anyhow::Result<()> {\n        let id = component_id.inner();\n        let tracked = self.clocks.contains_key(&component_id)\n            || self.actor_ids.iter().any(|actor_id| actor_id.inner() == id)\n            || self\n                .strategy_ids","sourceCodeStart":431,"sourceCodeEnd":467,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/system/src/python/registration.rs#L431-L467","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Make the Python class inherit from `nautilus_trader.common.actor.Actor` (or the appropriate Actor subclass)","Check you are passing an actor instance, not a class or a strategy","Verify your nautilus_trader Python package version matches the Rust core version","Inspect the chained `{e}` PyO3 downcast error for the exact type mismatch"],"exampleFix":"// before\nclass MyActor:  # not an Actor\n    ...\n// after\nfrom nautilus_trader.common.actor import Actor\nclass MyActor(Actor):\n    ...","handlingStrategy":"type-guard","validationCode":"from nautilus_trader.common.actor import Actor\nassert isinstance(obj, Actor), f\"{type(obj)} is not an Actor\"","typeGuard":"from nautilus_trader.common.actor import Actor\ndef is_pydata_actor(obj) -> bool:\n    return isinstance(obj, Actor)","tryCatchPattern":"try:\n    trader.add_data_actor(obj)\nexcept Exception as e:\n    if \"downcast\" in str(e):\n        raise TypeError(f\"{obj!r} must subclass Actor\") from e\n    raise","preventionTips":["Always subclass nautilus_trader.common.actor.Actor for data actors","Pass instances, not classes, to registration APIs","Keep nautilus_trader Python and core versions in sync"],"tags":["python","actor-registration","type-error"],"backgroundTag":"incompatible-source-type","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}