nautechsystems/nautilus_trader · error
data_type must have type_name
Error message
data_type must have type_name
What it means
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.
Source
Thrown at crates/model/src/data/mod.rs:812
serde_json::to_string(&serde_json::Value::Object(map))
}
/// Deserializes from JSON produced by `to_persistence_json`.
/// Accepts legacy JSON with `topic` (ignored); topic is rebuilt from `type_name` + metadata.
///
/// # Errors
///
/// Returns an error if the string is not valid JSON or missing required fields.
pub fn from_persistence_json(s: &str) -> Result<Self, anyhow::Error> {
let value: serde_json::Value =
serde_json::from_str(s).map_err(|e| anyhow::anyhow!("Invalid data_type JSON: {e}"))?;
let obj = value
.as_object()
.ok_or_else(|| anyhow::anyhow!("data_type must be a JSON object"))?;
let type_name = obj
.get("type_name")
.and_then(|v| v.as_str())
.ok_or_else(|| anyhow::anyhow!("data_type must have type_name"))?;
let metadata = obj.get("metadata").and_then(|m| {
if m.is_null() {
None
} else {
let p: Params = serde_json::from_value(m.clone()).ok()?;
if p.is_empty() { None } else { Some(p) }
}
});
let identifier = obj
.get("identifier")
.and_then(|v| v.as_str())
.map(String::from);
Ok(Self::new(type_name, metadata, identifier))
}
/// Returns the type name for the data type.
#[must_use]
pub fn type_name(&self) -> &str {View on GitHub (pinned to 18893faf8b)
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()`.
Example fix
// before
let dt = DataType::from_persistence_json(r#"{"metadata": null}"#)?;
// after
let dt = DataType::from_persistence_json(r#"{"type_name": "QuoteTick", "metadata": null}"#)?; Defensive patterns
Strategy: validation
Validate before calling
fn has_type_name(v: &serde_json::Value) -> bool {
v.get("type_name").and_then(|t| t.as_str()).map(|s| !s.is_empty()).unwrap_or(false)
} Type guard
fn type_name_of(v: &serde_json::Value) -> Option<&str> {
v.get("type_name").and_then(|t| t.as_str())
} Prevention
- 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.
When it happens
Trigger: 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).
Common situations: 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.
Understand the failure class
Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.
Related errors
- data_type must be a JSON object
- Execution schema version {} is newer than supported version
- Invalid `{SCHEMA_PARAM}` '{schema}'. Must be one of: {allowe
- Limit orders require a price
- Stop market orders require a trigger price
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/732746aeedddb49f.
Report an issue: GitHub.