nautechsystems/nautilus_trader · error
canonical diagnostic must be an object
Error message
canonical diagnostic must be an object
What it means
Each element of the canonical 'diagnostics' array must itself be a JSON object with exactly one field, 'code'. This error fires when an element of the array is a scalar, string, null, or array instead of an object.
Source
Thrown at crates/backtest/src/result.rs:410
values.iter().all(Value::is_string),
"canonical component field '{key}' must contain strings"
);
}
anyhow::ensure!(
object.get("trader_state").is_some_and(Value::is_string),
"canonical trader state must be a string"
);
Ok(())
}
fn validate_diagnostics(value: &Value) -> anyhow::Result<()> {
let diagnostics = value
.as_array()
.ok_or_else(|| anyhow::anyhow!("canonical diagnostics must be an array"))?;
for diagnostic in diagnostics {
let object = diagnostic
.as_object()
.ok_or_else(|| anyhow::anyhow!("canonical diagnostic must be an object"))?;
validate_fields(object, &["code"], "canonical diagnostic")?;
anyhow::ensure!(
object.get("code").and_then(Value::as_str) == Some("funding-settlement-failed"),
"unsupported canonical diagnostic code"
);
}
Ok(())
}
fn validate_run(value: &Value) -> anyhow::Result<()> {
let object = value
.as_object()
.ok_or_else(|| anyhow::anyhow!("canonical result run must be an object"))?;
validate_fields(
object,
&[
"backtest_end_ns",
"backtest_start_ns",View on GitHub (pinned to 18893faf8b)
Solutions
- Wrap each entry as an object: {"code": "..."} instead of a bare string
- Ensure nulls are never appended to the diagnostics array
- Fix the producer so every diagnostic is serialized as {"code": ...}
Example fix
// before
"diagnostics": ["funding-settlement-failed"]
// after
"diagnostics": [{"code": "funding-settlement-failed"}] Defensive patterns
Strategy: validation
Validate before calling
fn diagnostics_entries_are_objects(d: &[serde_json::Value]) -> bool {
d.iter().all(|x| x.is_object())
} Type guard
fn as_diag_object(v: &serde_json::Value) -> Option<&serde_json::Map<String, serde_json::Value>> { v.as_object() } Try / catch
match CanonicalResult::from_slice(&bytes) {
Ok(result) => /* use result */,
Err(e) if e.to_string().contains("diagnostic must be an object") => /* wrap bare entries as {"code": ...} */,
Err(e) => return Err(e.into()),
} Prevention
- Always serialize diagnostics as objects with a 'code' key, never bare strings
- Define a Diagnostic struct in the producer so the shape is enforced at compile time
- Validate each diagnostics element before writing the document
When it happens
Trigger: from_slice with "diagnostics": ["funding-settlement-failed"] (bare strings) or [null]; constructing a document where diagnostic entries were appended as raw strings.
Common situations: Simplifying diagnostics to plain strings when generating JSON; mixing diagnostic formats from different tools.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- canonical result components must be an object
- canonical result run must be an object
- filter {key:?} contains a non-string value
- Expected JSON object for contract
- Expected JSON array for contracts
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/6768aef211e5f358.
Report an issue: GitHub.