{"record":{"id":"2b72ffe9e4237b9f","repo":"nautechsystems/nautilus_trader","slug":"python-object-has-no-to-json-method-or-dict","errorCode":null,"errorMessage":"Python object has no to_json() method or __dict__ attribute","messagePattern":"Python object has no to_json\\(\\) method or __dict__ attribute","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/data/custom.rs","lineNumber":184,"sourceCode":"    fn ts_event(&self) -> UnixNanos {\n        self.cached_ts_event\n    }\n\n    fn to_json(&self) -> anyhow::Result<String> {\n        Python::attach(|py| {\n            let obj = self.py_object.bind(py);\n            // Call to_json() on the Python object if available\n            if obj.hasattr(\"to_json\")? {\n                let json_str: String = obj.call_method0(\"to_json\")?.extract()?;\n                Ok(json_str)\n            } else {\n                // Fallback: use Python's json module\n                let json_module = py.import(\"json\")?;\n                // Try to get a dict representation\n                let dict = if obj.hasattr(\"__dict__\")? {\n                    obj.getattr(\"__dict__\")?\n                } else {\n                    anyhow::bail!(\"Python object has no to_json() method or __dict__ attribute\");\n                };\n                let json_str: String = json_module.call_method1(\"dumps\", (dict,))?.extract()?;\n                Ok(json_str)\n            }\n        })\n    }\n\n    fn clone_arc(&self) -> Arc<dyn CustomDataTrait> {\n        Arc::new(self.clone())\n    }\n\n    fn eq_arc(&self, other: &dyn CustomDataTrait) -> bool {\n        // Equality by Python object identity only, to avoid false equality when two\n        // distinct Python objects share the same type name and timestamps.\n        if let Some(other_wrapper) = other.as_any().downcast_ref::<Self>() {\n            Python::attach(|py| {\n                let a = self.py_object.bind(py);\n                let b = other_wrapper.py_object.bind(py);","sourceCodeStart":166,"sourceCodeEnd":202,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/data/custom.rs#L166-L202","documentation":"CustomData::to_json serializes a Python-backed custom data object. It first tries the object's to_json() method, then falls back to json.dumps of the object's __dict__. If the Python object has neither a to_json() method nor a __dict__ attribute, this error is raised because no serialization path exists.","triggerScenarios":"Wrapping a Python object (typically one implemented with __slots__, a builtin type, or a Rust/exotic type without instance dict) in custom data and calling to_json()/to_json_py() on it.","commonSituations":"Using classes with __slots__ for memory efficiency; passing built-in objects (e.g. datetime without wrapping) as custom data; porting older custom data classes that never defined to_json.","solutions":["Implement a to_json() method on the Python class returning a JSON string.","Alternatively ensure the object is a normal class with instance attributes so __dict__ exists (remove __slots__ or add a dict-backed base).","Wrap the value in a simple serializable container class exposing to_json()."],"exampleFix":"// before\nclass MyData:\n    __slots__ = (\"x\",)\n    def __init__(self, x): self.x = x\n// after\nclass MyData:\n    def __init__(self, x): self.x = x\n    def to_json(self) -> str:\n        import json\n        return json.dumps({\"x\": self.x})","handlingStrategy":"type-guard","validationCode":"# Python\ndef is_json_serializable_custom_data(obj) -> bool:\n    return hasattr(obj, \"to_json\") or hasattr(obj, \"__dict__\")","typeGuard":"# Python\ndef has_json_repr(obj) -> bool:\n    return callable(getattr(obj, \"to_json\", None)) or hasattr(obj, \"__dict__\")","tryCatchPattern":"# Python\ntry:\n    data.to_json()\nexcept ValueError as e:\n    if \"to_json() method or __dict__\" in str(e):\n        raise TypeError(f\"{type(data).__name__} must define to_json() or use a plain class\") from e\n    raise","preventionTips":["Always implement to_json() on classes passed as custom data.","Avoid __slots__-only classes for custom data payloads.","Add a serialization round-trip test for every custom data type."],"tags":["python","json","serialization","custom-data"],"backgroundTag":"json-serialization-failed","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"}