{"record":{"id":"b728adc1c5e51aa2","repo":"nautechsystems/nautilus_trader","slug":"serialized-order-did-not-contain-an-object-core","errorCode":null,"errorMessage":"serialized order did not contain an object core","messagePattern":"serialized order did not contain an object core","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/backtest/src/result.rs","lineNumber":522,"sourceCode":"    }\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}\n\nfn optional_nanos(value: Option<UnixNanos>) -> Value {\n    value.map_or(Value::Null, |nanos| Value::String(nanos.to_string()))\n}\n\nfn canonical_order(order: &OrderAny) -> anyhow::Result<Value> {\n    let mut value = serde_json::to_value(order)?;\n    let payload = variant_payload_mut(&mut value)?;\n    let core = payload\n        .get_mut(\"core\")\n        .and_then(Value::as_object_mut)\n        .ok_or_else(|| anyhow::anyhow!(\"serialized order did not contain an object core\"))?;\n    set_decimal(core, \"avg_px\", order.avg_px());\n    set_decimal(core, \"slippage\", order.slippage());\n\n    if let Some(events) = core.get_mut(\"events\").and_then(Value::as_array_mut) {\n        for (source, encoded) in order.events().into_iter().zip(events) {\n            patch_order_event_decimals(source, encoded)?;\n        }\n    }\n    set_decimal_if_present(payload, \"limit_offset\", order.limit_offset());\n    set_decimal_if_present(payload, \"trailing_offset\", order.trailing_offset());\n    canonicalize_value(&mut value)?;\n    Ok(value)\n}\n\nfn canonical_fills(orders: &[OrderAny]) -> anyhow::Result<Vec<Value>> {\n    let mut fills = Vec::new();\n\n    for order in orders {","sourceCodeStart":504,"sourceCodeEnd":540,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/backtest/src/result.rs#L504-L540","documentation":"`canonical_order` serializes an OrderAny to JSON, locates its variant payload, and expects an inner `core` object containing the order's shared fields. This internal error is thrown when the serialized JSON has no `core` object inside the variant payload — meaning the serde representation of the order does not match the expected internally-tagged shape. It is an invariant violation rather than user input validation.","triggerScenarios":"Calling canonical_order (during canonical result document generation) with an OrderAny whose serde JSON lacks a `core` object in its variant payload — e.g. after a serde representation change of the order enum, a custom/foreign order variant, or tampered serialization.","commonSituations":"Mixing order types from a different nautilus version (serde format drift); a custom OrderAny payload that bypasses the standard order core; generated JSON wrapped or transformed by an intermediate layer that renamed `core`.","solutions":["Regenerate/serialize the order with the matching library version so the variant payload contains a `core` object","Check for version mismatch between the crate that constructed the order and the one canonicalizing it","Inspect the serde representation (serde_json::to_value(order)) to confirm the expected tagged shape","Avoid custom serialization wrappers around OrderAny before canonicalization"],"exampleFix":"// before (drifted serde shape)\n{\"order\": {\"limit\": {\"avg_px\": 1.0, ...}}}          // no core\n// after (expected shape)\n{\"order\": {\"limit\": {\"core\": {\"avg_px\": \"1.0\", ...}}}}","handlingStrategy":"try-catch","validationCode":"fn order_core_present(order: &OrderAny) -> anyhow::Result<bool> {\n    let value = serde_json::to_value(order)?;\n    Ok(value\n        .get(\"order\")\n        .or_else(|| value.get(\"limit\").or_else(|| value.get(\"market\"))\n            .map(|_| &value).unwrap_or(&value))\n        .pointer(\"/core\")\n        .map_or(false, serde_json::Value::is_object))\n}","typeGuard":"fn has_object_core(payload: &serde_json::Value) -> bool {\n    payload.get(\"core\").map_or(false, serde_json::Value::is_object)\n}","tryCatchPattern":"let canonical = canonical_order(&order).map_err(|e| {\n    if e.to_string().contains(\"did not contain an object core\") {\n        // log serde representation and crate versions for diagnosis\n    }\n    e\n})?;","preventionTips":["Keep order-construction and result-canonicalization crates on the same version","Do not wrap or re-tag OrderAny serialization with custom impls","Add a round-trip test: serialize an order of every variant and canonicalize it","Assert the expected tagged serde shape in CI"],"tags":["serde","internal","serialization","backtest"],"backgroundTag":"internal-invariant-violation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}