nautechsystems/nautilus_trader · error

canonical component field '{key}' must contain strings

Error message

canonical component field '{key}' must contain strings

What it means

After confirming the component ID fields are arrays, validate_components requires every element of actor_ids, exec_algorithm_ids, and strategy_ids to be a JSON string. Any number, boolean, null, or nested value inside these arrays triggers this error.

Source

Thrown at crates/backtest/src/result.rs:391

        .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 = diagnostic
            .as_object()

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Convert each element to a string (e.g. id.to_string()) before serializing
  2. Filter or fix null/non-string entries in the ID collections
  3. Fix the producer so component IDs are stored as strings end-to-end

Example fix

// before
"strategy_ids": [1, 2]
// after
"strategy_ids": ["1", "2"]
Defensive patterns

Strategy: validation

Validate before calling

fn component_ids_are_strings(c: &serde_json::Value) -> bool {
    ["actor_ids", "exec_algorithm_ids", "strategy_ids"].iter().all(|k| {
        c.get(k).and_then(|v| v.as_array()).map_or(false, |a| a.iter().all(|x| x.is_string()))
    })
}

Type guard

fn all_strings(a: &[serde_json::Value]) -> bool { 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 contain strings") => /* stringify array elements and retry */,
    Err(e) => return Err(e.into()),
}

Prevention

When it happens

Trigger: from_slice with e.g. "strategy_ids": [1, 2] or [null]; constructing a document from component collections containing numeric or non-string IDs.

Common situations: Numeric component IDs from an external system serialized as numbers; a null sneaking into a list during assembly.

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


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/bf5ea9a185f058d1. Report an issue: GitHub.