nautechsystems/nautilus_trader · error
canonical run field '{field}' is not a canonical unsigned de
Error message
canonical run field '{field}' is not a canonical unsigned decimal What it means
After confirming the field is a string, `validate_unsigned_decimal` enforces canonical formatting: the value must be exactly "0" or a non-empty digit-only string with no leading zero. This error is thrown for strings like "007", "1.5", "-3", " 12", "", or "1e3" — i.e. non-canonical representations of unsigned decimals. This keeps the canonical document byte-stable and deterministic.
Source
Thrown at crates/backtest/src/result.rs:479
);
anyhow::ensure!(
matches!(
object.get("outcome").and_then(Value::as_str),
Some("completed" | "failed" | "incomplete" | "stopped")
),
"unsupported canonical run outcome"
);
Ok(())
}
fn validate_unsigned_decimal(value: &Value, field: &str, nullable: bool) -> anyhow::Result<()> {
if nullable && value.is_null() {
return Ok(());
}
let value = value
.as_str()
.ok_or_else(|| anyhow::anyhow!("canonical run field '{field}' must be a decimal string"))?;
anyhow::ensure!(
value == "0"
|| (!value.is_empty()
&& !value.starts_with('0')
&& value.bytes().all(|byte| byte.is_ascii_digit())),
"canonical run field '{field}' is not a canonical unsigned decimal"
);
Ok(())
}
fn validate_statistics(value: &Value) -> anyhow::Result<()> {
let object = value
.as_object()
.ok_or_else(|| anyhow::anyhow!("canonical result statistics must be an object"))?;
validate_fields(
object,
&["general", "pnls", "returns", "returns_series"],
"canonical result statistics",
)?;View on GitHub (pinned to 18893faf8b)
Solutions
- Rewrite the value in canonical form: "0" or digits-only with no leading zeros (e.g. "042" -> "42")
- Regenerate the document with the canonical writer instead of hand-editing
- Normalize the string in a pre-processing step (strip leading zeros, reject non-digit characters) before validation
- Fix the producing code so it serializes integers with plain decimal formatting
Example fix
// before
{"run": {"total_orders": "0042"}}
// after
{"run": {"total_orders": "42"}} Defensive patterns
Strategy: validation
Validate before calling
fn is_canonical_unsigned_decimal(s: &str) -> bool {
s == "0" || (!s.is_empty() && !s.starts_with('0') && s.bytes().all(|b| b.is_ascii_digit()))
} Type guard
fn value_is_canonical_decimal(v: &serde_json::Value) -> bool {
v.as_str().map_or(false, is_canonical_unsigned_decimal)
} Try / catch
match validate_document(&doc) {
Err(e) if e.to_string().contains("canonical unsigned decimal") => {
// strip leading zeros / reformat the offending field and retry
}
other => other,
} Prevention
- Format integers with plain decimal formatting (no padding, no separators, no exponents)
- Never build ns-timestamp strings from float seconds
- Reject or normalize non-canonical numerics at document creation time
- Run the validator as part of your export pipeline to catch format drift early
When it happens
Trigger: Validating a run document whose iterations/total_events/total_orders/total_positions or backtest_start_ns/backtest_end_ns string is not a canonical unsigned decimal: leading zeros ("042"), floats ("3.14"), negatives ("-1"), whitespace, exponent notation, or scientific notation.
Common situations: Timestamps formatted with float seconds then stringified ("1720000000.5"); values formatted with thousands separators; numbers produced via toFixed/percent formatting; manual edits adding padding zeros; negative values from buggy counters.
Understand the failure class
Background: "Invalid ... format", "must be in format X", "does not look like a ..." — invalid argument format errors across CLI tools and libraries — this error's family across 17 libraries.
Related errors
- Polymarket market BUY amount {} pUSD truncates to zero at {L
- Cannot add a multi-currency spot instrument {instrument_id}
- invalid probability: must not be 1.0 (inverse would be zero)
- Price must be greater than 1.0 for lay liability calculation
- invalid {name}: must be non-zero
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/81a004d9da406d99.
Report an issue: GitHub.