{"record":{"id":"94fdc9bf37c31484","repo":"nautechsystems/nautilus_trader","slug":"failed-to-call-from-json-e","errorCode":null,"errorMessage":"Failed to call from_json: {e}","messagePattern":"Failed to call from_json: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/python/data/mod.rs","lineNumber":365,"sourceCode":"    value: &serde_json::Value,\n) -> Result<std::sync::Arc<dyn crate::data::CustomDataTrait>, anyhow::Error> {\n    use std::sync::Arc;\n\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)","sourceCodeStart":347,"sourceCodeEnd":383,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/python/data/mod.rs#L347-L383","documentation":"After parsing the JSON dict, py_json_deserialize_custom_data calls the registered Python class's from_json(py_dict) classmethod to build the instance. If that Python method raises or does not exist, the error is wrapped as 'Failed to call from_json: {e}'. This means the custom data class's Python-side contract is broken.","triggerScenarios":"register_custom_data_class was given a Python class that has no from_json classmethod, from_json has an incompatible signature, or from_json raises (KeyError on missing fields, TypeError on wrong types, validation errors) when given the deserialized dict.","commonSituations":"Custom data class written without the required from_json classmethod; Rust struct fields renamed/added so the Python from_json no longer matches the JSON keys; from_json expecting a JSON string but receiving a dict after a version change.","solutions":["Implement (or fix) from_json on the registered Python class as a classmethod accepting the dict produced by serialization.","Make from_json tolerant of missing/extra keys matching the Rust struct's serde field names (check rename_all attributes).","Test the class directly: MyClass.from_json(json.loads(MyClass(...).to_json())) in Python before registering.","Check for schema drift between the Rust struct and the Python class after upgrades and keep field names in sync."],"exampleFix":"// before: class lacks from_json\n#[pyclass]\nstruct MyData { /* ... */ }\n// after: add the contract on the Python side\nclass MyData:\n    @classmethod\n    def from_json(cls, data: dict) -> \"MyData\":\n        return cls(\n            value=data[\"value\"],           # keys must match serde field names\n            ts_event=data[\"ts_event\"],\n            ts_init=data[\"ts_init\"],\n        )","handlingStrategy":"validation","validationCode":"# verify before registering the class\nimport inspect, json\nassert hasattr(MyData, \"from_json\"), \"custom data class must define from_json classmethod\"\nsig = inspect.signature(MyData.from_json)\nassert \"data\" in sig.parameters, \"from_json must accept the deserialized dict\"","typeGuard":null,"tryCatchPattern":"match py_json_deserialize_custom_data(data_class, value) {\n    Ok(v) => v,\n    Err(e) if e.to_string().contains(\"Failed to call from_json\") => {\n        log::error!(\"custom data class from_json broken: {e}; check field names vs serde schema\");\n        Err(e)\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Every registered custom data class must implement from_json as a classmethod taking the dict.","Keep Python field names in sync with the Rust struct's serde attributes (rename_all).","Unit-test from_json against json.loads of a serialized instance before registration."],"tags":["python","json","custom-data","deserialization","pyo3"],"backgroundTag":"method-not-implemented","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"}