nautechsystems/nautilus_trader · error
invalid canonical backtest result JSON: {e}
Error message
invalid canonical backtest result JSON: {e} What it means
`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.
Source
Thrown at crates/backtest/src/result.rs:189
pub position_snapshots: Vec<Position>,
pub accounts: Vec<AccountAny>,
pub portfolio_snapshots: Vec<PortfolioSnapshot>,
pub statistics: PortfolioStatistics,
}
impl CanonicalBacktestResult {
/// Decodes canonical result bytes and verifies their envelope, normalization, and exact
/// encoding.
///
/// Inner records retain their NautilusTrader model serialization and are compared as semantic
/// content. Producers must use the version 1 writer rather than construct records independently.
///
/// # Errors
///
/// Returns an error if the bytes are not a canonical version 1 result.
pub fn from_slice(bytes: &[u8]) -> anyhow::Result<Self> {
let document: Value = serde_json::from_slice(bytes)
.map_err(|e| anyhow::anyhow!("invalid canonical backtest result JSON: {e}"))?;
validate_document(&document)?;
let mut normalized = document.clone();
canonicalize_document(&mut normalized)?;
anyhow::ensure!(
normalized == document,
"canonical backtest result violates the version 1 encoding rules"
);
let canonical = serde_json::to_vec(&normalized)?;
anyhow::ensure!(
canonical == bytes,
"canonical backtest result bytes do not use the canonical encoding"
);
Ok(Self { document })
}
/// Returns the canonical compact UTF-8 JSON bytes without trailing data.
///
/// # ErrorsView on GitHub (pinned to 18893faf8b)
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
Defensive patterns
Strategy: validation
Validate before calling
import json
def is_complete_json(path):
try:
with open(path, 'rb') as f:
json.loads(f.read().decode('utf-8-sig'))
return True
except Exception:
return False Try / catch
match BacktestResult::from_slice(&bytes) {
Err(e) if e.to_string().contains("invalid canonical backtest result JSON") => {
eprintln!("not valid JSON: {e:#}"); // fall back to from_state or re-run backtest
}
Err(e) => return Err(e),
Ok(r) => r,
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: JSON parse error: "Unexpected token" / "not valid JSON" / "failed to parse" — what JSON parsers are really complaining about — this error's family across 45 libraries.
Related errors
- Expected 2 token IDs, received {}
- Expected 2 outcomes, received {}
- Invalid `NautilusDataType`: '{s}'
- Failed to parse eth call response: {e} Raw response: {previe
- Failed to parse eth_call response
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/673c49330b48a0fe.
Report an issue: GitHub.