{"record":{"id":"951bdefed3ae2a48","repo":"nautechsystems/nautilus_trader","slug":"matching-engine-raw-id-exhausted-at-u32-max","errorCode":null,"errorMessage":"matching engine raw ID exhausted at u32::MAX","messagePattern":"matching engine raw ID exhausted at u32::MAX","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/backtest/src/exchange.rs","lineNumber":488,"sourceCode":"            .bar_adaptive_high_low_ordering(self.bar_adaptive_high_low_ordering)\n            .trade_execution(self.trade_execution)\n            .liquidity_consumption(self.liquidity_consumption)\n            .reject_stop_orders(self.reject_stop_orders)\n            .support_gtd_orders(self.support_gtd_orders)\n            .support_contingent_orders(self.support_contingent_orders)\n            .use_position_ids(self.use_position_ids)\n            .use_random_ids(self.use_random_ids)\n            .use_reduce_only(self.use_reduce_only)\n            .use_market_order_acks(self.use_market_order_acks)\n            .queue_position(self.queue_position)\n            .oto_full_trigger(self.oto_full_trigger)\n            .maybe_price_protection_points(price_protection)\n            .build();\n        let instrument_id = instrument.id();\n        let raw_id = self\n            .last_raw_id\n            .checked_add(1)\n            .ok_or_else(|| anyhow::anyhow!(\"matching engine raw ID exhausted at u32::MAX\"))?;\n        self.last_raw_id = raw_id;\n        let mut matching_engine = OrderMatchingEngine::new(\n            instrument.clone(),\n            raw_id,\n            self.fill_model.clone(),\n            self.fee_model.clone(),\n            self.book_type,\n            self.oms_type,\n            self.account_type,\n            self.clock.clone(),\n            Rc::clone(&self.cache),\n            matching_engine_config,\n        );\n\n        if let Some(handler) = &self.event_handler {\n            matching_engine.set_event_handler(Rc::clone(handler));\n        }\n        self.instruments.insert(instrument_id, instrument);","sourceCodeStart":470,"sourceCodeEnd":506,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/backtest/src/exchange.rs#L470-L506","documentation":"The backtest exchange assigns each newly added instrument a monotonically increasing u32 raw ID for its matching engine. When the internal counter has already reached u32::MAX, checked_add(1) overflows and this error is thrown instead of silently wrapping. It indicates the simulation has tried to register more instruments than can be addressed with a u32 identifier.","triggerScenarios":"Calling add_instrument (directly or via process_order_book_delta(s), process_order_book_depth10, process_quote_tick, process_trade_tick, or process_bar) after the exchange has already registered 4,294,967,295 instruments in a single run.","commonSituations":"Extremely long-running or replayed backtests that re-add instruments without resetting the exchange; a bug feeding the same deltas through process_order_book_delta repeatedly, each call registering a new instrument; synthetic data generators producing unbounded instrument IDs.","solutions":["Reduce the number of instruments registered in a single backtest run","Reuse existing instruments instead of re-adding them on every delta/tick","Create a fresh backtest exchange (resetting last_raw_id) for each run or chunk instead of reusing one across runs","If genuinely more than u32::MAX instruments are needed, this is unsupported; partition the workload across multiple exchange instances"],"exampleFix":"// before: re-adding the instrument on every delta\nfor delta in deltas { exchange.process_order_book_delta(delta)?; } // re-adds per symbol each time\n// after: add once, then only process deltas\nfor instrument in instruments { exchange.add_instrument(instrument)?; }\nfor delta in deltas { exchange.process_order_book_delta(delta)?; }","handlingStrategy":"validation","validationCode":"// before adding instruments, ensure the run stays far below u32::MAX\nassert!(instruments.len() < u32::MAX as usize, \"too many instruments for one exchange\");\n// and add each instrument only once\nlet added: HashSet<InstrumentId> = HashSet::new();","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Add each instrument exactly once, before the data loop","Create a new exchange per backtest run instead of reusing one across replays","Watch for code paths that re-register instruments on every delta/tick"],"tags":["backtest","overflow","u32","resource-exhaustion"],"backgroundTag":"value-out-of-range","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}