nautechsystems/nautilus_trader · error
canonical result summary must be an object
Error message
canonical result summary must be an object
What it means
`validate_document` requires the canonical result's `summary` field to be a JSON object whose values are all strings (it carries display/summary data). If `summary` is missing, not an object, or contains non-string values, this error is returned.
Source
Thrown at crates/backtest/src/result.rs:349
"fills",
"orders",
"portfolio_snapshots",
"position_snapshots",
"positions",
] {
anyhow::ensure!(
object.get(key).is_some_and(Value::is_array),
"canonical result field '{key}' must be an array"
);
}
validate_components(object.get("components").expect("validated field"))?;
validate_diagnostics(object.get("diagnostics").expect("validated field"))?;
validate_run(object.get("run").expect("validated field"))?;
validate_statistics(object.get("statistics").expect("validated field"))?;
let summary = object
.get("summary")
.and_then(Value::as_object)
.ok_or_else(|| anyhow::anyhow!("canonical result summary must be an object"))?;
anyhow::ensure!(
summary.values().all(Value::is_string),
"canonical result summary values must be strings"
);
Ok(())
}
fn validate_fields(
object: &Map<String, Value>,
expected: &[&str],
context: &str,
) -> anyhow::Result<()> {
let actual = object.keys().map(String::as_str).collect::<BTreeSet<_>>();
let expected = expected.iter().copied().collect::<BTreeSet<_>>();
anyhow::ensure!(
actual == expected,
"{context} fields do not match the version 1 schema"
);View on GitHub (pinned to 18893faf8b)
Solutions
- Convert all summary values to strings (e.g. format floats with a fixed representation) before writing the document
- Ensure `summary` exists and is an object even when empty: `{}`
- Regenerate the result with the canonical writer rather than assembling summary by hand
- Validate with a quick check: `all(isinstance(v, str) for v in doc["summary"].values())`
Example fix
// before
"summary": {"pnl": 1234.5}
// after
"summary": {"pnl": "1234.5"} Defensive patterns
Strategy: type-guard
Validate before calling
s = doc.get("summary")
assert isinstance(s, dict) and all(isinstance(v, str) for v in s.values()), "summary must be object of strings" Type guard
fn has_valid_summary(doc: &serde_json::Value) -> bool {
doc.get("summary").and_then(|v| v.as_object())
.is_some_and(|s| s.values().all(serde_json::Value::is_string))
} Try / catch
match BacktestResult::from_slice(&bytes) {
Err(e) if e.to_string().contains("summary must be an object") => {
eprintln!("invalid summary section: {e:#}");
}
Err(e) => return Err(e),
Ok(r) => r,
} Prevention
- Stringify all summary values at write time with a stable format
- Always emit `summary` as an object, `{}` if empty
- Never insert raw floats/NaN into summary fields
When it happens
Trigger: Loading a document where `summary` is absent or is an array/scalar, or where a summary value is a number/bool/null/nested object (e.g. putting a numeric metric directly into summary instead of stringifying it).
Common situations: Custom writers adding numeric metrics to summary without string conversion; post-processing that inserts raw floats (NaN ratios, PnL) into summary; dropping summary during a partial export.
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
- canonical backtest result must be a JSON object
- canonical result field '{key}' must be an array
- canonical run configuration ID must be a string or null
- canonical trader ID must be a string
- canonical result statistics must be an object
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/2c1a262e7be1760b.
Report an issue: GitHub.