{"record":{"id":"732746aeedddb49f","repo":"nautechsystems/nautilus_trader","slug":"data-type-must-have-type-name","errorCode":null,"errorMessage":"data_type must have type_name","messagePattern":"data_type must have type_name","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/model/src/data/mod.rs","lineNumber":812,"sourceCode":"        serde_json::to_string(&serde_json::Value::Object(map))\n    }\n\n    /// Deserializes from JSON produced by `to_persistence_json`.\n    /// Accepts legacy JSON with `topic` (ignored); topic is rebuilt from `type_name` + metadata.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the string is not valid JSON or missing required fields.\n    pub fn from_persistence_json(s: &str) -> Result<Self, anyhow::Error> {\n        let value: serde_json::Value =\n            serde_json::from_str(s).map_err(|e| anyhow::anyhow!(\"Invalid data_type JSON: {e}\"))?;\n        let obj = value\n            .as_object()\n            .ok_or_else(|| anyhow::anyhow!(\"data_type must be a JSON object\"))?;\n        let type_name = obj\n            .get(\"type_name\")\n            .and_then(|v| v.as_str())\n            .ok_or_else(|| anyhow::anyhow!(\"data_type must have type_name\"))?;\n        let metadata = obj.get(\"metadata\").and_then(|m| {\n            if m.is_null() {\n                None\n            } else {\n                let p: Params = serde_json::from_value(m.clone()).ok()?;\n                if p.is_empty() { None } else { Some(p) }\n            }\n        });\n        let identifier = obj\n            .get(\"identifier\")\n            .and_then(|v| v.as_str())\n            .map(String::from);\n        Ok(Self::new(type_name, metadata, identifier))\n    }\n\n    /// Returns the type name for the data type.\n    #[must_use]\n    pub fn type_name(&self) -> &str {","sourceCodeStart":794,"sourceCodeEnd":830,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/model/src/data/mod.rs#L794-L830","documentation":"A generic deserialization guard in from_persistence_json: the JSON string (as produced by to_persistence_json, or a legacy form) is missing the required 'type_name' field needed to rebuild the DataType's topic. The input at fault is a persisted data_type JSON object lacking type_name.","triggerScenarios":"Calling `DataType::from_persistence_json` with an object like `{\"metadata\": {}}` that lacks `\"type_name\"`, or where `type_name` is a non-string value (number, object, null).","commonSituations":"Hand-written or hand-edited persistence JSON missing the required key; a custom serializer writing a different key name (e.g. `typeName` or `type`); partially migrated records from an older schema.","solutions":["Add the `type_name` field with a string value to the JSON object.","Check the key casing/naming (`type_name`, snake_case) matches what the library expects.","Re-serialize the original DataType using `DataType`'s persistence serializer rather than hand-writing JSON.","Validate the object shape before calling: check `obj.get(\"type_name\").and_then(|v| v.as_str()).is_some()`."],"exampleFix":"// before\nlet dt = DataType::from_persistence_json(r#\"{\"metadata\": null}\"#)?;\n\n// after\nlet dt = DataType::from_persistence_json(r#\"{\"type_name\": \"QuoteTick\", \"metadata\": null}\"#)?;","handlingStrategy":"validation","validationCode":"fn has_type_name(v: &serde_json::Value) -> bool {\n    v.get(\"type_name\").and_then(|t| t.as_str()).map(|s| !s.is_empty()).unwrap_or(false)\n}","typeGuard":"fn type_name_of(v: &serde_json::Value) -> Option<&str> {\n    v.get(\"type_name\").and_then(|t| t.as_str())\n}","tryCatchPattern":null,"preventionTips":["Use the library's serializer to produce DataType JSON instead of hand-writing it.","Keep key names snake_case and consistent with the library schema.","Add a schema check when migrating records from older formats."],"tags":["rust","json","schema","missing-field"],"backgroundTag":"missing-required-argument","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"}