nautechsystems/nautilus_trader · error
canonical trader ID must be a string
Error message
canonical trader ID must be a string
What it means
`validate_run` requires the `trader_id` field of the canonical run object to be a JSON string. This error is thrown when the field exists but holds another JSON type (number, null, object, array) or is a non-string value. Trader IDs identify the trading node instance that produced the backtest result, and the canonical format mandates a string so consumers can parse them into the domain TraderId type.
Source
Thrown at crates/backtest/src/result.rs:458
for key in [
"iterations",
"total_events",
"total_orders",
"total_positions",
] {
validate_unsigned_decimal(object.get(key).expect("validated field"), key, false)?;
}
for key in ["backtest_start_ns", "backtest_end_ns"] {
validate_unsigned_decimal(object.get(key).expect("validated field"), key, true)?;
}
anyhow::ensure!(
object
.get("run_config_id")
.is_some_and(|value| value.is_null() || value.is_string()),
"canonical run configuration ID must be a string or null"
);
anyhow::ensure!(
object.get("trader_id").is_some_and(Value::is_string),
"canonical trader ID must be a string"
);
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 = valueView on GitHub (pinned to 18893faf8b)
Solutions
- Set run.trader_id to the trader ID as a JSON string (e.g. "TRADER-001")
- Regenerate the canonical document using the library's own result writer
- Pre-validate the JSON and convert non-string trader IDs to strings before validation
- Verify the source of the document matches the current canonical schema version
Example fix
// before
{"run": {"trader_id": null, ...}}
// after
{"run": {"trader_id": "TRADER-001", ...}} Defensive patterns
Strategy: validation
Validate before calling
fn trader_id_is_valid(run: &serde_json::Value) -> bool {
run.get("trader_id").is_some_and(serde_json::Value::is_string)
} Type guard
fn is_nonempty_string(v: &serde_json::Value) -> bool {
v.as_str().map_or(false, |s| !s.is_empty())
} Try / catch
match validate_document(&doc) {
Err(e) if e.to_string().contains("trader ID must be a string") => {
// stringify run.trader_id and retry
}
other => other,
} Prevention
- Serialize trader_id via its Display/to_string form
- Never emit identifiers as raw JSON numbers
- Validate fixtures against the current schema before use
- Keep import/export code aware of the canonical field types
When it happens
Trigger: Passing a canonical result document to `validate_document` (via `validate_run`) where `run.trader_id` is not a JSON string — e.g. null, a number, or a nested object. Typically the document was not produced by this library's canonical serializer.
Common situations: Hand-built result JSON for testing; results migrated from an older format with a differently-typed trader identifier; a serialization tool that drops quotes around identifiers; fixtures copied from another schema.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- canonical backtest result must be a JSON object
- canonical result field '{key}' must be an array
- canonical result summary must be an object
- canonical run configuration ID must be a string or null
- canonical result statistics must be an object
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/70430d6d6ca73171.
Report an issue: GitHub.