{"record":{"id":"bd6d2ef069219bfd","repo":"nautechsystems/nautilus_trader","slug":"only-one-run-config-per-backtestnode-is-supported","errorCode":null,"errorMessage":"Only one run config per BacktestNode is supported (kernel MessageBus is a thread-local singleton)","messagePattern":"Only one run config per BacktestNode is supported \\(kernel MessageBus is a thread-local singleton\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/backtest/src/node.rs","lineNumber":313,"sourceCode":"            let ids: Vec<String> = instr_ids.iter().map(ToString::to_string).collect();\n            anyhow::bail!(\n                \"No instruments found in catalog for requested IDs: [{}]\",\n                ids.join(\", \")\n            );\n        }\n\n        for instrument in instruments {\n            engine.add_instrument(&instrument)?;\n        }\n    }\n\n    Ok(engine)\n}\n\nfn validate_configs(configs: &[BacktestRunConfig]) -> anyhow::Result<()> {\n    // Kernel initialization sets a thread-local MessageBus that can only be\n    // initialized once per thread, so multiple engines cannot coexist\n    anyhow::ensure!(\n        configs.len() <= 1,\n        \"Only one run config per BacktestNode is supported \\\n         (kernel MessageBus is a thread-local singleton)\"\n    );\n\n    let mut seen_ids = AHashSet::new();\n\n    for config in configs {\n        anyhow::ensure!(\n            seen_ids.insert(config.id()),\n            \"Duplicate run config ID '{}'\",\n            config.id()\n        );\n\n        let venue_names: Vec<String> = config\n            .venues()\n            .iter()\n            .map(|v| v.name().to_string())","sourceCodeStart":295,"sourceCodeEnd":331,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/backtest/src/node.rs#L295-L331","documentation":"BacktestNode only supports a single run config because the kernel MessageBus is a thread-local singleton that can only be initialized once per thread; multiple engines cannot coexist. validate_configs rejects any config list longer than one.","triggerScenarios":"Passing two or more BacktestRunConfig values to `BacktestNode::new`, expecting multi-run (parameter sweep / portfolio of backtests) behavior.","commonSituations":"Migrating code that assumed multi-run support; building a batch of scenario configs in a loop and collecting them all into one node; parallel backtest sweeps.","solutions":["Create one BacktestNode per run config and run them sequentially","Run each config in its own thread/process if parallelism is needed","Aggregate results yourself after running nodes one at a time","Check the current API/docs whether multi-run support has since been added"],"exampleFix":"// before\nlet node = BacktestNode::new(vec![cfg_a, cfg_b])?;\n// after\nfor cfg in [cfg_a, cfg_b] {\n    let node = BacktestNode::new(vec![cfg])?;\n    node.run()?;\n}","handlingStrategy":"validation","validationCode":"if configs.len() > 1 { panic!(\"BacktestNode supports only one run config\"); }","typeGuard":null,"tryCatchPattern":"match BacktestNode::new(configs) {\n    Ok(node) => node,\n    Err(e) if e.to_string().contains(\"Only one run config\") => {\n        for cfg in configs { BacktestNode::new(vec![cfg])?.run()?; }\n        unreachable!()\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Model multi-scenario runs as sequential nodes, one config each","Use threads or processes for parallel backtests instead of multiple configs in one node"],"tags":["backtest","configuration","limitation"],"backgroundTag":"unsupported-operation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}