{"record":{"id":"673c49330b48a0fe","repo":"nautechsystems/nautilus_trader","slug":"invalid-canonical-backtest-result-json-e","errorCode":null,"errorMessage":"invalid canonical backtest result JSON: {e}","messagePattern":"invalid canonical backtest result JSON: (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/backtest/src/result.rs","lineNumber":189,"sourceCode":"    pub position_snapshots: Vec<Position>,\n    pub accounts: Vec<AccountAny>,\n    pub portfolio_snapshots: Vec<PortfolioSnapshot>,\n    pub statistics: PortfolioStatistics,\n}\n\nimpl CanonicalBacktestResult {\n    /// Decodes canonical result bytes and verifies their envelope, normalization, and exact\n    /// encoding.\n    ///\n    /// Inner records retain their NautilusTrader model serialization and are compared as semantic\n    /// content. Producers must use the version 1 writer rather than construct records independently.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the bytes are not a canonical version 1 result.\n    pub fn from_slice(bytes: &[u8]) -> anyhow::Result<Self> {\n        let document: Value = serde_json::from_slice(bytes)\n            .map_err(|e| anyhow::anyhow!(\"invalid canonical backtest result JSON: {e}\"))?;\n        validate_document(&document)?;\n        let mut normalized = document.clone();\n        canonicalize_document(&mut normalized)?;\n        anyhow::ensure!(\n            normalized == document,\n            \"canonical backtest result violates the version 1 encoding rules\"\n        );\n        let canonical = serde_json::to_vec(&normalized)?;\n        anyhow::ensure!(\n            canonical == bytes,\n            \"canonical backtest result bytes do not use the canonical encoding\"\n        );\n        Ok(Self { document })\n    }\n\n    /// Returns the canonical compact UTF-8 JSON bytes without trailing data.\n    ///\n    /// # Errors","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/backtest/src/result.rs#L171-L207","documentation":"`BacktestResult::from_slice` parses bytes that are supposed to be an already-canonical version-1 backtest result document. If the bytes are not valid JSON at all, serde_json fails and this message wraps the parse error. Canonical results are re-validated, canonicalized, and byte-compared, so input must be exact canonical JSON.","triggerScenarios":"Calling `BacktestResult::from_slice` with bytes that are not valid JSON: a truncated file, a log line or text file, binary/protobuf bytes, or JSON produced with trailing garbage after the document.","commonSituations":"Loading a backtest result file that was truncated by an interrupted write; feeding a non-JSON export (CSV, msgpack) into from_slice; reading a file with a BOM or appended log output.","solutions":["Inspect the bytes/file and confirm it is complete valid JSON (e.g. `json.loads` it in Python or `jq . file.json`)","Regenerate the result via the backtest node or `BacktestResult::from_state` instead of from_slice if you only have in-memory state","Strip any BOM, trailing whitespace/garbage, or concatenated JSON before parsing","Ensure the producer wrote with the canonical writer rather than hand-serializing"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import json\ndef is_complete_json(path):\n    try:\n        with open(path, 'rb') as f:\n            json.loads(f.read().decode('utf-8-sig'))\n        return True\n    except Exception:\n        return False","typeGuard":null,"tryCatchPattern":"match BacktestResult::from_slice(&bytes) {\n    Err(e) if e.to_string().contains(\"invalid canonical backtest result JSON\") => {\n        eprintln!(\"not valid JSON: {e:#}\"); // fall back to from_state or re-run backtest\n    }\n    Err(e) => return Err(e),\n    Ok(r) => r,\n}","preventionTips":["Write result files atomically (temp file + rename) to avoid truncation","Never pipe results through logging or text transforms","Verify saved files parse with `jq .` before archiving them"],"tags":["json","parsing","backtest","result"],"backgroundTag":"json-parse-error","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"}