{"record":{"id":"4a33a030671aded0","repo":"nautechsystems/nautilus_trader","slug":"failed-to-extract-pydataactor-e-4a33a0","errorCode":null,"errorMessage":"Failed to extract PyDataActor: {e}","messagePattern":"Failed to extract PyDataActor: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/common/src/python/actor.rs","lineNumber":2842,"sourceCode":"/// Applies optional config overrides and stores a weak reference to the Python instance used for\n/// method dispatch. Missing or unreadable attributes are ignored, and non-boolean `log_events` or\n/// `log_commands` values leave the existing settings unchanged. When neither the config nor\n/// `DataActor.__init__` supplies an ID, the runtime class name replaces the shared default so\n/// subclasses that skip the base initializer still receive distinct IDs.\n///\n/// # Errors\n///\n/// Returns an error if the actor cannot be extracted, its configured `actor_id` is neither an\n/// [`ActorId`] nor a valid ID string, its class-derived ID is invalid, or its Python instance\n/// cannot be weakly referenced.\npub fn prepare_python_actor(\n    actor_obj: &Bound<'_, PyAny>,\n    config: Option<&Bound<'_, PyAny>>,\n) -> anyhow::Result<ActorId> {\n    let mut actor = actor_obj\n        .extract::<PyRefMut<PyDataActor>>()\n        .map_err(Into::<PyErr>::into)\n        .map_err(|e| anyhow::anyhow!(\"Failed to extract PyDataActor: {e}\"))?;\n\n    if let Some(config) = config {\n        if let Some(actor_id) = config\n            .getattr(\"actor_id\")\n            .ok()\n            .filter(|actor_id| !actor_id.is_none())\n        {\n            let actor_id = if let Ok(actor_id) = actor_id.extract::<ActorId>() {\n                actor_id\n            } else if let Ok(actor_id) = actor_id.extract::<String>() {\n                ActorId::new_checked(&actor_id)?\n            } else {\n                anyhow::bail!(\"Invalid `actor_id` type\");\n            };\n            actor.set_actor_id(actor_id);\n        }\n\n        if let Some(log_events) = extract_bool_config_attr(config, \"log_events\") {","sourceCodeStart":2824,"sourceCodeEnd":2860,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/common/src/python/actor.rs#L2824-L2860","documentation":"Raised when Rust code cannot extract a `PyRefMut<PyDataActor>` from a Python object passed as an actor during actor registration (registering the actor and reading its id). `extract` fails when the Python object is not actually an instance of the `PyDataActor` class (or a subclass) expected by the Rust binding, so registration aborts with this anyhow-wrapped error.","triggerScenarios":"Passing a Python object to the actor registration function (crates/common/src/python/actor.rs:2842) that is not a `PyDataActor` subclass — e.g. a plain Actor/Strategy class not derived from the required Python base, a wrong wrapper, or passing None/misordered arguments so the wrong object lands in `actor_obj`.","commonSituations":"Mixing actor base classes across API versions (actor created from the wrong factory or module), forgetting to subclass the required Python `Actor`/`DataActor` base that is backed by `PyDataActor`, or refactors that changed the registration entry point while callers still pass legacy objects.","solutions":["Ensure the object passed to registration is created via the correct Python factory/base class that produces a `PyDataActor`-backed object (subclass the provided Actor/DataActor base, do not pass arbitrary objects).","Check that you are passing the actor object as the correct argument (not swapped with config) to the registration call.","Verify you are not mixing versions of the library where the actor class layout changed; reinstall/rebuild the package consistently.","Print `type(actor_obj)` and its MRO in Python to confirm it derives from the expected base before registering."],"exampleFix":"# before\nactor = MyCustomThing()          # not a PyDataActor-backed instance\nregister_actor(actor, config)\n\n# after\nfrom nautilus_trader.common.actor import Actor\n\nclass MyActor(Actor):            # backed by PyDataActor on the Rust side\n    ...\n\nactor = MyActor(config=config)\nregister_actor(actor, config)","handlingStrategy":"type-guard","validationCode":"# Python, before registration\nfrom nautilus_trader.common.actor import Actor\nassert isinstance(actor, Actor), f'{type(actor)} is not a supported Actor type'","typeGuard":"def is_registrable_actor(obj) -> bool:\n    from nautilus_trader.common.actor import Actor\n    return isinstance(obj, Actor)","tryCatchPattern":"match register_actor(&actor_obj, config) {\n    Err(e) => eprintln!(\"actor registration failed: {e:#}\"),\n    Ok(id) => println!(\"registered actor {id}\"),\n}","preventionTips":["Always subclass the library-provided Actor/DataActor base classes","Create actors via the documented factory functions, not raw classes","Confirm argument order (actor, config) when calling registration","Keep library versions consistent across install and build"],"tags":["python","rust-bridge","actor","type-mismatch","registration"],"backgroundTag":"type-mismatch","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"}