nautechsystems/nautilus_trader · error
data_type must be a JSON object
Error message
data_type must be a JSON object
What it means
After the JSON parses, `from_persistence_json` requires the top-level value to be a JSON object (a map of fields for the DataType). If the string parses to a scalar, array, or null instead, this error is raised.
Source
Thrown at crates/model/src/data/mod.rs:808
"identifier".to_string(),
serde_json::Value::String(id.clone()),
);
}
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))
}View on GitHub (pinned to 18893faf8b)
Solutions
- Ensure the persisted form is a full object: `{"type_name": "...", "metadata": {...}}`, not just the type name.
- Re-persist the DataType with the current library's serializer so the on-disk format matches.
- Check that you're loading the whole record and not an inner field of it.
- Validate the parsed value's shape before calling, e.g. `serde_json::from_str::<serde_json::Value>(s)?.is_object()`.
Example fix
// before
let dt = DataType::from_persistence_json(r#""QuoteTick""#)?;
// after
let dt = DataType::from_persistence_json(r#"{"type_name": "QuoteTick"}"#)?; Defensive patterns
Strategy: type-guard
Validate before calling
fn is_object_json(s: &str) -> bool {
serde_json::from_str::<serde_json::Value>(s).map(|v| v.is_object()).unwrap_or(false)
} Type guard
fn as_datatype_object(v: &serde_json::Value) -> Option<&serde_json::Map<String, serde_json::Value>> {
v.as_object()
} Prevention
- Always serialize the full DataType object, not just its type name string.
- Round-trip test your persistence format across versions.
- Validate the parsed shape before handing the string to from_persistence_json.
When it happens
Trigger: Passing JSON like `"SomeType"`, `["a","b"]`, `123`, or `null` to `DataType::from_persistence_json` — anything that is valid JSON but not an object.
Common situations: Persisting only the type_name string and trying to reload it as a full DataType; a serialization change between versions that wrote arrays/scalars; slicing the wrong portion of a JSON document.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Invalid data_type JSON: {e}
- data_type must have type_name
- Failed to concatenate stream batches: {e}
- Failed to merge custom data type metadata: {e}
- height must be positive, was {self.height}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/b18d60e855e3ae74.
Report an issue: GitHub.