{"record":{"id":"6768aef211e5f358","repo":"nautechsystems/nautilus_trader","slug":"canonical-diagnostic-must-be-an-object","errorCode":null,"errorMessage":"canonical diagnostic must be an object","messagePattern":"canonical diagnostic must be an object","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/backtest/src/result.rs","lineNumber":410,"sourceCode":"            values.iter().all(Value::is_string),\n            \"canonical component field '{key}' must contain strings\"\n        );\n    }\n    anyhow::ensure!(\n        object.get(\"trader_state\").is_some_and(Value::is_string),\n        \"canonical trader state must be a string\"\n    );\n    Ok(())\n}\n\nfn validate_diagnostics(value: &Value) -> anyhow::Result<()> {\n    let diagnostics = value\n        .as_array()\n        .ok_or_else(|| anyhow::anyhow!(\"canonical diagnostics must be an array\"))?;\n    for diagnostic in diagnostics {\n        let object = diagnostic\n            .as_object()\n            .ok_or_else(|| anyhow::anyhow!(\"canonical diagnostic must be an object\"))?;\n        validate_fields(object, &[\"code\"], \"canonical diagnostic\")?;\n        anyhow::ensure!(\n            object.get(\"code\").and_then(Value::as_str) == Some(\"funding-settlement-failed\"),\n            \"unsupported canonical diagnostic code\"\n        );\n    }\n    Ok(())\n}\n\nfn validate_run(value: &Value) -> anyhow::Result<()> {\n    let object = value\n        .as_object()\n        .ok_or_else(|| anyhow::anyhow!(\"canonical result run must be an object\"))?;\n    validate_fields(\n        object,\n        &[\n            \"backtest_end_ns\",\n            \"backtest_start_ns\",","sourceCodeStart":392,"sourceCodeEnd":428,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/backtest/src/result.rs#L392-L428","documentation":"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.","triggerScenarios":"from_slice with \"diagnostics\": [\"funding-settlement-failed\"] (bare strings) or [null]; constructing a document where diagnostic entries were appended as raw strings.","commonSituations":"Simplifying diagnostics to plain strings when generating JSON; mixing diagnostic formats from different tools.","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\": ...}"],"exampleFix":"// before\n\"diagnostics\": [\"funding-settlement-failed\"]\n// after\n\"diagnostics\": [{\"code\": \"funding-settlement-failed\"}]","handlingStrategy":"validation","validationCode":"fn diagnostics_entries_are_objects(d: &[serde_json::Value]) -> bool {\n    d.iter().all(|x| x.is_object())\n}","typeGuard":"fn as_diag_object(v: &serde_json::Value) -> Option<&serde_json::Map<String, serde_json::Value>> { v.as_object() }","tryCatchPattern":"match CanonicalResult::from_slice(&bytes) {\n    Ok(result) => /* use result */,\n    Err(e) if e.to_string().contains(\"diagnostic must be an object\") => /* wrap bare entries as {\"code\": ...} */,\n    Err(e) => return Err(e.into()),\n}","preventionTips":["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"],"tags":["json","type-mismatch","schema-validation"],"backgroundTag":"type-mismatch","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"}