nautechsystems/nautilus_trader · error
canonical result run must be an object
Error message
canonical result run must be an object
What it means
The 'run' section of a canonical result must be a JSON object holding the run metadata (backtest_end_ns, backtest_start_ns, iterations, outcome, run_config_id, total_events, total_orders, total_positions, trader_id). validate_run throws this when 'run' is null, an array, or any other non-object type, during both from_state construction and from_slice parsing.
Source
Thrown at crates/backtest/src/result.rs:423
.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",
"iterations",
"outcome",
"run_config_id",
"total_events",
"total_orders",
"total_positions",
"trader_id",
],
"canonical result run",
)?;
for key in [
"iterations",View on GitHub (pinned to 18893faf8b)
Solutions
- Change run to an object containing exactly the nine required schema fields
- Fix the serializer so run metadata is emitted as a JSON map
- Regenerate the document with the library's canonical writer
Example fix
// before
"run": []
// after
"run": {"backtest_end_ns": null, "backtest_start_ns": null, "iterations": "1", "outcome": "completed", "run_config_id": null, "total_events": "0", "total_orders": "0", "total_positions": "0", "trader_id": "TRADER-001"} Defensive patterns
Strategy: validation
Validate before calling
fn run_is_object(doc: &serde_json::Value) -> bool {
doc.get("run").map_or(false, |v| v.is_object())
} Type guard
fn is_object(v: &serde_json::Value) -> bool { v.is_object() } Try / catch
match CanonicalResult::from_slice(&bytes) {
Ok(result) => /* use result */,
Err(e) if e.to_string().contains("run must be an object") => /* rebuild 'run' as an object with the nine schema fields */,
Err(e) => return Err(e.into()),
} Prevention
- Serialize run metadata as a JSON map with exactly the nine schema fields
- Never emit null or an array for the run section
- Prefer the library's from_state constructor over hand-assembling documents
When it happens
Trigger: from_slice with "run": [] or "run": null; constructing a document where the run metadata was serialized as a list or omitted to null.
Common situations: Hand-assembled result JSON with run as an array of key/value pairs; a producer from another schema nesting run differently.
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 diagnostic 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/191b0358a42eca37.
Report an issue: GitHub.