nautechsystems/nautilus_trader · error

Failed to serialize config value: {e}

Error message

Failed to serialize config value: {e}

What it means

Raised by `config_value_to_py` when a single config value cannot be serialized to JSON with `serde_json::to_string` as part of converting the Rust config map into a Python dict. Values like StrategyId are handled specially; anything else goes through serde_json, which fails for non-serializable types (e.g. maps with non-string keys, arbitrary Rust types without Serialize).

Source

Thrown at crates/backtest/src/python/node.rs:598

) -> anyhow::Result<Bound<'py, PyAny>> {
    if key == "actor_id"
        && let Some(actor_id) = value.as_str()
    {
        return Ok(ActorId::new_checked(actor_id)?
            .into_pyobject(py)?
            .into_any());
    }

    if key == "strategy_id"
        && let Some(strategy_id) = value.as_str()
    {
        return Ok(StrategyId::new_checked(strategy_id)?
            .into_pyobject(py)?
            .into_any());
    }

    let json_str = serde_json::to_string(value)
        .map_err(|e| anyhow::anyhow!("Failed to serialize config value: {e}"))?;
    Ok(PyModule::import(py, "json")?
        .call_method("loads", (json_str,), None)?
        .into_any())
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Convert non-string map keys to Strings before putting them in the config
  2. Sanitize floats: replace NaN/Infinity with valid values or omit the entry
  3. Use only JSON-compatible types (string, bool, i64/u64, f64 finite, Vec, String-keyed map) for config values
  4. If it is a custom type, implement Serialize/Deserialize for it in a JSON-compatible form

Example fix

// before
let config: HashMap<String, ConfigValue> = ...; config.insert("ratios".into(), map keyed by u32)
// after
let string_keyed: BTreeMap<String, f64> = inner.into_iter().map(|(k, v)| (k.to_string(), v)).collect();
Defensive patterns

Strategy: validation

Validate before calling

// Pre-validate config values are JSON-serializable
serde_json::to_string(&value).map_err(|e| format!("config value '{key}' not serializable: {e}"))?;

Type guard

fn is_json_serializable(v: &ConfigValue) -> bool { serde_json::to_string(v).is_ok() }

Try / catch

match create_importable_component(...) {
    Err(e) if e.to_string().contains("Failed to serialize config value") => {
        eprintln!("non-JSON config value: {e:#}");
    }
    Err(e) => return Err(e),
    Ok(v) => v,
}

Prevention

When it happens

Trigger: Passing a config entry whose value cannot be JSON-serialized: a HashMap/BTreeMap with non-string keys (serde_json requires string keys for maps), a float that is NaN/Infinity (serde_json rejects them by default), or a custom type not implementing serde::Serialize in a way JSON supports.

Common situations: Users constructing a backtest node config programmatically in Rust with nested maps keyed by integers/enums; NaN appearing from computed default values; custom config structs with unsupported field types (e.g. tuple keys, non-string enum keys).

Understand the failure class

Background: json.Marshal / "failed to marshal" errors in Go: why "unsupported type" happens and how to fix it — this error's family across 22 libraries.

Related errors


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