{"record":{"id":"7f04d1ee2c40b1ea","repo":"nautechsystems/nautilus_trader","slug":"failed-to-create-wrapper-e","errorCode":null,"errorMessage":"Failed to create wrapper: {e}","messagePattern":"Failed to create wrapper: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/python/data/mod.rs","lineNumber":368,"sourceCode":"\n    use crate::data::PythonCustomDataWrapper;\n\n    pyo3::Python::attach(|py| {\n        let json_str = serde_json::to_string(&value)?;\n        let json_module = py\n            .import(\"json\")\n            .map_err(|e| anyhow::anyhow!(\"Failed to import json: {e}\"))?;\n        let py_dict = json_module\n            .call_method1(\"loads\", (json_str,))\n            .map_err(|e| anyhow::anyhow!(\"Failed to parse JSON: {e}\"))?;\n\n        let instance = data_class\n            .bind(py)\n            .call_method1(\"from_json\", (py_dict,))\n            .map_err(|e| anyhow::anyhow!(\"Failed to call from_json: {e}\"))?;\n\n        let wrapper = PythonCustomDataWrapper::new(py, &instance)\n            .map_err(|e| anyhow::anyhow!(\"Failed to create wrapper: {e}\"))?;\n\n        Ok(Arc::new(wrapper) as Arc<dyn crate::data::CustomDataTrait>)\n    })\n}\n\n/// Encodes `CustomData` items to `RecordBatch` via Python `encode_record_batch_py`.\n#[allow(unsafe_code)]\n#[cfg(all(feature = \"python\", feature = \"arrow\"))]\nfn py_encode_custom_data_to_record_batch(\n    items: &[std::sync::Arc<dyn crate::data::CustomDataTrait>],\n) -> Result<arrow::record_batch::RecordBatch, anyhow::Error> {\n    pyo3::Python::attach(|py| {\n        let py_items: Result<Vec<_>, _> = items.iter().map(|item| item.to_pyobject(py)).collect();\n        let py_items = py_items.map_err(|e| anyhow::anyhow!(\"Failed to convert to Python: {e}\"))?;\n        let py_list = pyo3::types::PyList::new(py, &py_items)\n            .map_err(|e| anyhow::anyhow!(\"Failed to create list: {e}\"))?;\n\n        let first = items","sourceCodeStart":350,"sourceCodeEnd":386,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/python/data/mod.rs#L350-L386","documentation":"When deserializing custom data from a JSON dict via a registered Python class, NautilusTrader calls the class's `from_json` method and then wraps the resulting Python object in `PythonCustomDataWrapper` so it can be stored as an `Arc<dyn CustomDataTrait>`. This error is raised when the wrapper construction itself fails, meaning the Python object returned by `from_json` is not a valid custom-data instance (e.g. missing required attributes/methods the wrapper expects). The underlying Python exception message is embedded in `{e}`.","triggerScenarios":"Calling a deserialization path (via `register_custom_data_class`-registered types, e.g. `Data.from_json`/custom data decode) where the registered Python class's `from_json` returns an object that `PythonCustomDataWrapper::new` cannot wrap — such as a plain dict, None, or an object lacking the expected nautilus custom-data interface.","commonSituations":"A user-defined data class was registered but its `from_json` implementation returns the wrong type (dict instead of an instance, or None on parse failure); after upgrading nautilus the wrapper contract gained new required methods the old class does not implement; class returns an instance of a different class than the registered one.","solutions":["Check the embedded `{e}` Python traceback: fix `from_json` so it returns a fully constructed instance of the registered data class (not a dict or None).","Verify the registered class implements the full custom-data interface expected by PythonCustomDataWrapper (all required properties/methods like ts_init, type name, etc.).","Call the class's `from_json` directly in Python with a sample dict and inspect the returned object's type and attributes.","Re-register the class with `register_custom_data_class` after fixing it, and rerun the deserialization."],"exampleFix":"# before\nclass MyData:\n    @classmethod\n    def from_json(cls, data):\n        return data  # returns a dict -> wrapper fails\n\n# after\nclass MyData:\n    @classmethod\n    def from_json(cls, data):\n        return cls(**data)  # returns a proper instance","handlingStrategy":"try-catch","validationCode":"obj = MyClass.from_json(sample_dict)\nassert isinstance(obj, MyClass), f\"from_json returned {type(obj)}\"\nassert hasattr(obj, \"ts_init\")","typeGuard":"def is_valid_custom_data(obj) -> bool:\n    return isinstance(obj, MyClass) and hasattr(obj, \"ts_init\")","tryCatchPattern":"try:\n    item = Data.from_json(payload, MyData)\nexcept Exception as e:\n    logger.error(f\"custom data wrap failed: {e}\")\n    raise ValueError(\"from_json must return a MyData instance\") from e","preventionTips":["Ensure from_json always returns a constructed class instance, never a dict or None","Implement the full custom-data interface (ts_init, type name, etc.) on registered classes","Unit-test from_json/to_json round-trips for every registered class"],"tags":["python","pyo3","custom-data","deserialization"],"backgroundTag":"unexpected-response-shape","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}