nautechsystems/nautilus_trader · error
No matching engine found for instrument {}
Error message
No matching engine found for instrument {} What it means
The backtest exchange processes a data delta whose instrument is not present in the cache, so it cannot create (or find) a matching engine for that instrument. The exchange lazily adds a matching engine only when the instrument for the data's instrument_id exists in the cache; when cache.instrument() returns None it fails with this error. It prevents book/quote/trade data for unknown instruments from silently being dropped.
Source
Thrown at crates/backtest/src/exchange.rs:890
/// Processes a single order book delta.
///
/// # Errors
///
/// Returns an error if module pre-processing or matching engine processing fails.
pub fn process_order_book_delta(&mut self, delta: OrderBookDelta) -> anyhow::Result<()> {
self.pre_process_modules(&Data::BookDelta(delta))?;
if !self.matching_engines.contains_key(&delta.instrument_id) {
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
///View on GitHub (pinned to 18893faf8b)
Solutions
- Load instrument definitions into the cache before feeding data (e.g. pass instruments via the BacktestEngine config add_instrument or ensure the data catalog/instrument provider loads them).
- Verify the instrument_id in the delta exactly matches a cached instrument (venue and symbol, case-sensitive).
- Log the missing instrument_id and compare against cache.instrument_ids() to find the mismatch.
- If the data legitimately has no instrument definition, filter those deltas out before passing them to the exchange.
Example fix
// before exchange.process_order_book_delta(&delta)?; // delta for BTCUSDT.BINANCE, instrument never added // after engine.add_instrument(test_instrument_btcusdt_binance()); // or configure instrument provider exchange.process_order_book_delta(&delta)?;
Defensive patterns
Strategy: validation
Validate before calling
fn ensure_instrument_cached(cache: &Cache, instrument_id: &InstrumentId) -> anyhow::Result<()> {
if cache.instrument(instrument_id).is_none() {
anyhow::bail!("Instrument {instrument_id} not in cache; load definitions before feeding data");
}
Ok(())
} Type guard
let Some(instrument) = cache.instrument(&delta.instrument_id) else {
anyhow::bail!("Skipping delta for unknown instrument {}", delta.instrument_id);
}; Try / catch
match exchange.process_order_book_delta(&delta) {
Ok(()) => {},
Err(e) if e.to_string().contains("No matching engine found") => {
log::warn!("skipping unregistered instrument delta: {e}");
}
Err(e) => return Err(e),
} Prevention
- Always load the full instrument catalog before streaming market data into the backtest.
- Preflight-compare the set of instrument_ids in your data files against cache.instrument_ids().
- Use a single instrument provider configuration so data venue suffixes and definitions stay in sync.
When it happens
Trigger: Calling SimulatedExchange process functions such as process_order_book_delta (exchange.rs:890) with an OrderBookDelta whose instrument_id was never added via add_instrument, and no instrument with that ID exists in the provided cache.
Common situations: Replaying recorded data where the instrument definitions file was not loaded first; instrument_id venue/symbol casing mismatch between data and instrument definitions; loading data for a venue that was not registered in the backtest config; renamed or delisted instruments in historical datasets.
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
- Matching engine not found for instrument {order_instrument_i
- Matching engine not found for instrument {instrument_id}
- Matching engine should be initialized
- Cannot handle command: {command:?}
- Latency model should be initialized
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/9f5fd436fc855431.
Report an issue: GitHub.