nautechsystems/nautilus_trader · error
canonical result summary values must be strings
Error message
canonical result summary values must be strings
What it means
During validation of a canonical backtest result document, the 'summary' entry must be a JSON object whose every value is a string. The library writes summaries as string-keyed/string-valued maps (produced via canonical_summary), so any non-string value (number, bool, null, array, nested object) means the document was hand-edited or produced by an incompatible writer. Thrown by validate_document, which runs both when a document is constructed (from_state) and when one is parsed (from_slice).
Source
Thrown at crates/backtest/src/result.rs:350
"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"
);
Ok(())View on GitHub (pinned to 18893faf8b)
Solutions
- Quote every value in the summary object so all values are JSON strings (convert numbers with .to_string() before writing)
- Regenerate the document with the library's own canonicalization path instead of hand-editing
- Check the schema field equals the current CANONICAL_SCHEMA version and re-run any migration tooling
Example fix
// before
"summary": {"total_pnl": 1250.5}
// after
"summary": {"total_pnl": "1250.5"} Defensive patterns
Strategy: validation
Validate before calling
fn summary_values_are_strings(doc: &serde_json::Value) -> bool {
doc.get("summary")
.and_then(serde_json::Value::as_object)
.map(|s| s.values().all(serde_json::Value::is_string))
.unwrap_or(false)
} Type guard
fn is_string_map(v: &serde_json::Value) -> bool {
v.as_object().map_or(false, |o| o.values().all(|x| x.is_string()))
} Try / catch
match CanonicalResult::from_slice(&bytes) {
Ok(result) => /* use result */,
Err(e) if e.to_string().contains("summary values must be strings") => /* re-quote summary values or regenerate document */,
Err(e) => return Err(e.into()),
} Prevention
- Always serialize summary metrics with .to_string() so values are quoted
- Never hand-edit canonical result JSON; regenerate it via the library
- Validate documents against the v1 schema before feeding them to from_slice
When it happens
Trigger: Calling CanonicalResult::from_slice on JSON where summary contains a non-string value (e.g. "summary": {"total_pnl": 123} instead of "123"), or feeding a summary map with nested/null values into document construction.
Common situations: Hand-editing a result JSON file; generating the file with an older or external tool that writes numeric metrics unquoted; merging summaries from another schema version.
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 canonical backtest result JSON: {e}
- canonical backtest result violates the version 1 encoding ru
- canonical backtest result bytes do not use the canonical enc
- canonical backtest result must be a JSON object
- canonical result field '{key}' must be an array
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/0e306a8c385288b3.
Report an issue: GitHub.