nautechsystems/nautilus_trader · error

Duplicate run config ID '{}'

Error message

Duplicate run config ID '{}'

What it means

validate_configs found two BacktestRunConfig entries sharing the same id string; engines are keyed by config id, so duplicates would collide and the node refuses to build.

Source

Thrown at crates/backtest/src/node.rs:322

        }
    }

    Ok(engine)
}

fn validate_configs(configs: &[BacktestRunConfig]) -> anyhow::Result<()> {
    // Kernel initialization sets a thread-local MessageBus that can only be
    // initialized once per thread, so multiple engines cannot coexist
    anyhow::ensure!(
        configs.len() <= 1,
        "Only one run config per BacktestNode is supported \
         (kernel MessageBus is a thread-local singleton)"
    );

    let mut seen_ids = AHashSet::new();

    for config in configs {
        anyhow::ensure!(
            seen_ids.insert(config.id()),
            "Duplicate run config ID '{}'",
            config.id()
        );

        let venue_names: Vec<String> = config
            .venues()
            .iter()
            .map(|v| v.name().to_string())
            .collect();

        for data_config in config.data() {
            if let (Some(start), Some(end)) = (data_config.start_time(), data_config.end_time()) {
                anyhow::ensure!(
                    start <= end,
                    "Data config start_time ({start}) must be <= end_time ({end})"
                );
            }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Assign a unique id to every BacktestRunConfig (e.g. append an index or scenario name)
  2. Check loops that build configs so the id varies per iteration
  3. Deduplicate configs by id before constructing the node

Example fix

// before
for scenario in scenarios {
    configs.push(BacktestRunConfig::new("run", ...));
}
// after
for (i, scenario) in scenarios.iter().enumerate() {
    configs.push(BacktestRunConfig::new(format!("run-{i}"), ...));
}
Defensive patterns

Strategy: validation

Validate before calling

let mut seen = std::collections::HashSet::new();
for c in &configs { assert!(seen.insert(c.id()), "duplicate run id: {}", c.id()); }

Prevention

When it happens

Trigger: Passing two configs whose `id()` returns the same value to `BacktestNode::new` — e.g. cloning a config template and forgetting to change its id, or building configs in a loop with a constant id.

Common situations: Copy-pasted config templates; loop-generated configs using a fixed name; deserialized configs from a file where ids were duplicated.

Understand the failure class

Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.

Related errors


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