nautechsystems/nautilus_trader · critical
Execution client should be initialized
Error message
Execution client should be initialized
What it means
The backtest exchange panicked because a trading command required a portfolio execution client, but `self.exec_client` was `None`. In NautilusTrader's backtest engine the SimulatedExchange needs an initialized execution client to resolve the account that will process order submissions. This is an internal invariant of the backtest engine: `execute` was called before the client was wired up.
Source
Thrown at crates/backtest/src/exchange.rs:1872
return;
}
TradingCommand::ModifyOrders(mut command) => {
command
.modifies
.retain(|modify| !self.process_modify_submitted_order(modify));
if command.modifies.is_empty() {
return;
}
TradingCommand::ModifyOrders(command)
}
command => command,
};
let account_id = if let Some(exec_client) = &self.exec_client {
exec_client.account_id()
} else {
panic!("Execution client should be initialized");
};
if let TradingCommand::SubmitOrderList(ref command) = command {
let mut orders: Vec<OrderAny> = self
.cache
.borrow()
.orders_for_ids(&command.order_list.client_order_ids, command);
for order in &mut orders {
let order_instrument_id = order.instrument_id();
if let Some(matching_engine) = self.matching_engines.get_mut(&order_instrument_id) {
matching_engine.process_order(order, account_id);
} else {
panic!("Matching engine not found for instrument {order_instrument_id}");
}
}
return;View on GitHub (pinned to 18893faf8b)
Solutions
- Add the execution client to the backtest before executing commands (e.g. add a `SimulatedExchangeConfig`/venue with execution enabled or call the engine's exec-client registration API).
- Ensure `BacktestEngine.add_venue(...)` (or equivalent setup) runs before any `execute`/command submission.
- Check the order of initialization so `exec_client` is set before the data loop starts processing commands.
Example fix
// before let mut engine = BacktestEngine::new(); engine.add_data(...); engine.run(); // panic: no exec client // after let mut engine = BacktestEngine::new(); engine.add_venue(SimulatedExchangeConfig::default()); engine.add_data(...); engine.run();
Defensive patterns
Strategy: validation
Validate before calling
// before running the backtest assert!(engine.exec_client_account_id().is_some(), "Add a venue/exec client config before executing commands");
Prevention
- Always configure venues via `add_venue` before `run()`
- Keep backtest setup in one ordered function: venues -> data -> strategies -> run
- Cover engine construction in an integration smoke test that submits an order
When it happens
Trigger: Calling `SimulatedExchange.execute(...)` with a `SubmitOrderList` (or other `TradingCommand`) when no execution client was registered via `set_exec_client(...)` / the builder was not fully configured.
Common situations: Programmatically constructing a `BacktestEngine` or `SimulatedExchange` and forgetting to add the execution client/venue configuration; constructing an exchange by hand in tests without calling the exec-client setter; version changes in the backtest builder API where the setup call was renamed or dropped.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Latency model should be initialized
- Cannot handle command: {command:?}
- Matching engine not found for instrument {order_instrument_i
- Matching engine not found for instrument {instrument_id}
- Matching engine should be initialized
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/b4f994f356766653.
Report an issue: GitHub.