nautechsystems/nautilus_trader · error
Failed to create wrapper: {e}
Error message
Failed to create wrapper: {e} What it means
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}`.
Source
Thrown at crates/model/src/python/data/mod.rs:368
use crate::data::PythonCustomDataWrapper;
pyo3::Python::attach(|py| {
let json_str = serde_json::to_string(&value)?;
let json_module = py
.import("json")
.map_err(|e| anyhow::anyhow!("Failed to import json: {e}"))?;
let py_dict = json_module
.call_method1("loads", (json_str,))
.map_err(|e| anyhow::anyhow!("Failed to parse JSON: {e}"))?;
let instance = data_class
.bind(py)
.call_method1("from_json", (py_dict,))
.map_err(|e| anyhow::anyhow!("Failed to call from_json: {e}"))?;
let wrapper = PythonCustomDataWrapper::new(py, &instance)
.map_err(|e| anyhow::anyhow!("Failed to create wrapper: {e}"))?;
Ok(Arc::new(wrapper) as Arc<dyn crate::data::CustomDataTrait>)
})
}
/// Encodes `CustomData` items to `RecordBatch` via Python `encode_record_batch_py`.
#[allow(unsafe_code)]
#[cfg(all(feature = "python", feature = "arrow"))]
fn py_encode_custom_data_to_record_batch(
items: &[std::sync::Arc<dyn crate::data::CustomDataTrait>],
) -> Result<arrow::record_batch::RecordBatch, anyhow::Error> {
pyo3::Python::attach(|py| {
let py_items: Result<Vec<_>, _> = items.iter().map(|item| item.to_pyobject(py)).collect();
let py_items = py_items.map_err(|e| anyhow::anyhow!("Failed to convert to Python: {e}"))?;
let py_list = pyo3::types::PyList::new(py, &py_items)
.map_err(|e| anyhow::anyhow!("Failed to create list: {e}"))?;
let first = itemsView on GitHub (pinned to 18893faf8b)
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.
Example fix
# before
class MyData:
@classmethod
def from_json(cls, data):
return data # returns a dict -> wrapper fails
# after
class MyData:
@classmethod
def from_json(cls, data):
return cls(**data) # returns a proper instance Defensive patterns
Strategy: try-catch
Validate before calling
obj = MyClass.from_json(sample_dict)
assert isinstance(obj, MyClass), f"from_json returned {type(obj)}"
assert hasattr(obj, "ts_init") Type guard
def is_valid_custom_data(obj) -> bool:
return isinstance(obj, MyClass) and hasattr(obj, "ts_init") Try / catch
try:
item = Data.from_json(payload, MyData)
except Exception as e:
logger.error(f"custom data wrap failed: {e}")
raise ValueError("from_json must return a MyData instance") from e Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Failed to call from_json: {e}
- Failed to import json: {e}
- Failed to parse JSON: {e}
- Failed to convert to Python: {e}
- Failed to create list: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/7f04d1ee2c40b1ea.
Report an issue: GitHub.