{"record":{"id":"026a27964c331764","repo":"nautechsystems/nautilus_trader","slug":"canonical-result-statistics-must-be-an-object","errorCode":null,"errorMessage":"canonical result statistics must be an object","messagePattern":"canonical result statistics must be an object","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/backtest/src/result.rs","lineNumber":492,"sourceCode":"        return Ok(());\n    }\n    let value = value\n        .as_str()\n        .ok_or_else(|| anyhow::anyhow!(\"canonical run field '{field}' must be a decimal string\"))?;\n    anyhow::ensure!(\n        value == \"0\"\n            || (!value.is_empty()\n                && !value.starts_with('0')\n                && value.bytes().all(|byte| byte.is_ascii_digit())),\n        \"canonical run field '{field}' is not a canonical unsigned decimal\"\n    );\n    Ok(())\n}\n\nfn validate_statistics(value: &Value) -> anyhow::Result<()> {\n    let object = value\n        .as_object()\n        .ok_or_else(|| anyhow::anyhow!(\"canonical result statistics must be an object\"))?;\n    validate_fields(\n        object,\n        &[\"general\", \"pnls\", \"returns\", \"returns_series\"],\n        \"canonical result statistics\",\n    )?;\n\n    for key in [\"general\", \"pnls\", \"returns\"] {\n        anyhow::ensure!(\n            object.get(key).is_some_and(Value::is_object),\n            \"canonical statistics field '{key}' must be an object\"\n        );\n    }\n    anyhow::ensure!(\n        object.get(\"returns_series\").is_some_and(Value::is_array),\n        \"canonical returns series must be an array\"\n    );\n    Ok(())\n}","sourceCodeStart":474,"sourceCodeEnd":510,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/backtest/src/result.rs#L474-L510","documentation":"`validate_statistics` checks the `statistics` section of a canonical backtest result. The whole section must be a JSON object; this error is thrown when it is instead an array, string, number, boolean, or null. The statistics block is expected to contain the sub-objects general/pnls/returns plus the returns_series array, so a non-object makes the document unusable.","triggerScenarios":"Passing a canonical result document to validate_document where `statistics` is not a JSON object — e.g. an empty array [], a null, or a string. Typically from a mismatched schema version or a document whose statistics section was replaced/corrupted.","commonSituations":"Old result formats where statistics was an array of metrics; documents assembled by hand where statistics was omitted and defaulted to null; a script that assigned the wrong container type when aggregating stats.","solutions":["Ensure the statistics section is a JSON object with keys general, pnls, returns, and returns_series","Regenerate the canonical result with the current library version","Migrate/transform old-format statistics arrays into the object shape before validation","Check that no post-processing step replaced or nulled the statistics field"],"exampleFix":"// before\n{\"statistics\": []}\n// after\n{\"statistics\": {\"general\": {}, \"pnls\": {}, \"returns\": {}, \"returns_series\": []}}","handlingStrategy":"validation","validationCode":"fn statistics_shape_is_valid(doc: &serde_json::Value) -> bool {\n    doc.get(\"statistics\").map_or(false, serde_json::Value::is_object)\n}","typeGuard":"fn is_object(v: &serde_json::Value) -> bool { v.is_object() }","tryCatchPattern":"match validate_document(&doc) {\n    Err(e) if e.to_string().contains(\"statistics must be an object\") => {\n        // rebuild statistics section as an object and retry\n    }\n    other => other,\n}","preventionTips":["Emit statistics as an object with the required keys general/pnls/returns/returns_series","Default empty statistics to {} rather than null or []","Validate documents produced by older formats before migration","Keep a schema test that serializes a sample result and validates it"],"tags":["json","validation","schema","backtest"],"backgroundTag":"schema-validation-failed","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}