nautechsystems/nautilus_trader · error
canonical component field '{key}' must be an array
Error message
canonical component field '{key}' must be an array What it means
Within the canonical 'components' object, the fields actor_ids, exec_algorithm_ids, and strategy_ids must each be a JSON array of strings. This error fires when one of these fields exists but is not an array (null, string, object, or a scalar). validate_components enforces it during document construction and parsing.
Source
Thrown at crates/backtest/src/result.rs:390
let object = value
.as_object()
.ok_or_else(|| anyhow::anyhow!("canonical result components must be an object"))?;
validate_fields(
object,
&[
"actor_ids",
"exec_algorithm_ids",
"strategy_ids",
"trader_state",
],
"canonical result components",
)?;
for key in ["actor_ids", "exec_algorithm_ids", "strategy_ids"] {
let values = object
.get(key)
.and_then(Value::as_array)
.ok_or_else(|| anyhow::anyhow!("canonical component field '{key}' must be an array"))?;
anyhow::ensure!(
values.iter().all(Value::is_string),
"canonical component field '{key}' must contain strings"
);
}
anyhow::ensure!(
object.get("trader_state").is_some_and(Value::is_string),
"canonical trader state must be a string"
);
Ok(())
}
fn validate_diagnostics(value: &Value) -> anyhow::Result<()> {
let diagnostics = value
.as_array()
.ok_or_else(|| anyhow::anyhow!("canonical diagnostics must be an array"))?;
for diagnostic in diagnostics {
let object = diagnosticView on GitHub (pinned to 18893faf8b)
Solutions
- Wrap the value in an array: use ["S-1"] not "S-1"
- Ensure null is replaced by an empty array [] for these three fields
- Fix the producer code so ID collections are always serialized as JSON arrays of strings
Example fix
// before "strategy_ids": "S-1" // after "strategy_ids": ["S-1"]
Defensive patterns
Strategy: validation
Validate before calling
fn component_id_fields_are_arrays(c: &serde_json::Value) -> bool {
["actor_ids", "exec_algorithm_ids", "strategy_ids"].iter().all(|k| {
c.get(k).map_or(false, |v| v.is_array())
})
} Type guard
fn is_string_array(v: &serde_json::Value) -> bool {
v.as_array().map_or(false, |a| a.iter().all(|x| x.is_string()))
} Try / catch
match CanonicalResult::from_slice(&bytes) {
Ok(result) => /* use result */,
Err(e) if e.to_string().contains("must be an array") => /* wrap the offending field in an array */,
Err(e) => return Err(e.into()),
} Prevention
- Never collapse a single-element ID list into a scalar
- Use [] instead of null for empty ID collections
- Serialize ID collections as Vec<String> in the producer
When it happens
Trigger: from_slice with e.g. "components": {"strategy_ids": "S-1", ...} or "actor_ids": null; constructing a document where a component ID list was serialized as a single string or map.
Common situations: Collapsing a single-element list to a scalar when generating JSON; another writer emitting ID maps (object keyed by ID) instead of arrays.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- canonical component field '{key}' must contain strings
- canonical diagnostics must be an array
- filter {key:?} contains a non-string value
- Expected JSON object for contract
- Expected JSON array for contracts
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/abb096eaa23d5bbe.
Report an issue: GitHub.