nautechsystems/nautilus_trader · critical

Matching engine not found for instrument {order_instrument_i

Error message

Matching engine not found for instrument {order_instrument_id}

What it means

While submitting an order list, the exchange could not find a `MatchingEngine` registered for the order's instrument ID and panicked. Each traded instrument in the backtest needs a matching engine that simulates order matching; submitting orders for an instrument with no engine means the venue cannot process them.

Source

Thrown at crates/backtest/src/exchange.rs:1886

        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;
        }

        if let Some(matching_engine) = self.matching_engines.get_mut(&instrument_id) {
            match command {
                TradingCommand::SubmitOrder(command) => {
                    let mut order = self
                        .cache
                        .borrow()
                        .order(&command.client_order_id)
                        .map(|o| o.clone())
                        .expect("Order must exist in cache");
                    matching_engine.process_order(&mut order, account_id);
                }
                TradingCommand::ModifyOrder(ref command) => {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Register the instrument in the venue configuration (`add_venue` with the instrument) so a matching engine is created.
  2. Verify every order's `instrument_id` exactly matches a registered instrument.
  3. Validate instrument coverage before the run (compare cache instruments to venue-registered instruments).

Example fix

// before
engine.add_data(quote_data); // instrument on data only
engine.run(); // panic: no matching engine
// after
engine.add_venue(SimulatedExchangeConfig {
    instruments: vec![instrument],
    ..Default::default()
});
engine.add_data(quote_data);
engine.run();
Defensive patterns

Strategy: validation

Validate before calling

// before submitting
let registered: HashSet<InstrumentId> = venue.instruments().iter().map(|i| i.id()).collect();
for order in orders {
    assert!(registered.contains(&order.instrument_id()), "instrument not registered: {}", order.instrument_id());
}

Prevention

When it happens

Trigger: `SubmitOrderList` command where one of the orders' `instrument_id` has no entry in `exchange.matching_engines` (never registered via the venue config).

Common situations: Orders created for an instrument not declared in the backtest venue configuration; typo'd or synthesized instrument IDs; running a backtest against data from an instrument that was not added to the exchange config.

Understand the failure class

Background: 'Could not be found', 'does not exist', 'not found in database': the resource-not-found family when an ID, slug, key, or URI lookup comes back empty — this error's family across 20 libraries.

Related errors


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