nautechsystems/nautilus_trader · error

Matching engine should be initialized

Error message

Matching engine should be initialized

What it means

The instrument for the delta was found (or already added), but no matching engine is registered in the exchange's matching_engines map for that instrument_id, so the delta cannot be routed. In practice this means the instrument exists in the cache but the exchange never built a matching engine for it — an internal wiring/initialization gap between add_instrument and the engines map.

Source

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

            let instrument = {
                let cache = self.cache.as_ref().borrow();
                cache.instrument(&delta.instrument_id).cloned()
            };

            if let Some(instrument) = instrument {
                self.add_instrument(instrument)?;
            } else {
                anyhow::bail!(
                    "No matching engine found for instrument {}",
                    delta.instrument_id
                );
            }
        }

        if let Some(matching_engine) = self.matching_engines.get_mut(&delta.instrument_id) {
            matching_engine.process_order_book_delta(&delta)?;
        } else {
            anyhow::bail!("Matching engine should be initialized");
        }
        Ok(())
    }

    /// Processes a batch of order book deltas.
    ///
    /// # Errors
    ///
    /// Returns an error if module pre-processing or matching engine processing fails.
    pub fn process_order_book_deltas(&mut self, deltas: &OrderBookDeltas) -> anyhow::Result<()> {
        self.pre_process_modules(&Data::BookDeltas(Box::new(deltas.clone())))?;

        if !self.matching_engines.contains_key(&deltas.instrument_id) {
            let instrument = {
                let cache = self.cache.as_ref().borrow();
                cache.instrument(&deltas.instrument_id).cloned()
            };

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure instruments are registered through SimulatedExchange::new/add_instrument so a matching engine is created per instrument.
  2. Check that the exchange was configured with the correct book type, OMS type, and fee model matching the instrument's venue.
  3. Inspect self.matching_engines keys after setup and confirm the target instrument_id is present before feeding data.
  4. Recreate the exchange via the standard BacktestEngine add_instrument flow rather than mutating the cache directly.

Example fix

// before
cache.add_instrument(&instrument); // engine map not populated
exchange.process_order_book_delta(&delta)?; // Matching engine should be initialized

// after
engine.add_instrument(instrument.clone()); // goes through add_instrument -> matching_engines.insert
exchange.process_order_book_delta(&delta)?;
Defensive patterns

Strategy: validation

Validate before calling

if !exchange.matching_engines().contains_key(&delta.instrument_id) {
    anyhow::bail!("Matching engine not initialized for {}", delta.instrument_id);
}

Try / catch

if let Err(e) = exchange.process_order_book_delta(&delta) {
    if e.to_string().contains("should be initialized") {
        log::error!("Exchange setup incomplete: {e}");
        return Err(e);
    }
    return Err(e);
}

Prevention

When it happens

Trigger: Calling process_order_book_delta (exchange.rs:900) for an instrument that add_instrument accepted but for which no entry exists in self.matching_engines — e.g. the instrument was added to the cache without going through the exchange's engine-construction path.

Common situations: Adding instruments directly to the cache instead of via the exchange; a partially constructed exchange reused after a failed prior setup; custom exchange code that bypasses add_instrument; replaying data for an instrument type not supported by any configured matching engine (e.g. no book type/OMS configured for that venue).

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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