{"record":{"id":"9b16b7ef1a65e460","repo":"nautechsystems/nautilus_trader","slug":"cannot-batch-modify-empty-order-list","errorCode":null,"errorMessage":"Cannot batch modify empty order list","messagePattern":"Cannot batch modify empty order list","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/trading/src/strategy/mod.rs","lineNumber":464,"sourceCode":"    /// Batch modifies multiple orders for the same instrument.\n    ///\n    /// Each tuple is `(client_order_id, quantity, price, trigger_price)`.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the strategy is not registered, the orders span multiple instruments,\n    /// contain emulated/local orders, or a child modify is invalid.\n    fn modify_orders(\n        &mut self,\n        updates: Vec<BatchModifyOrder>,\n        client_id: Option<ClientId>,\n        params: Option<Params>,\n    ) -> anyhow::Result<()>\n    where\n        Self: StrategyNative,\n    {\n        if updates.is_empty() {\n            anyhow::bail!(\"Cannot batch modify empty order list\");\n        }\n\n        let (trader_id, strategy_id, ts_init) = {\n            let core = StrategyNative::strategy_core_mut(self);\n            (\n                registered_trader_id(core)?,\n                registered_strategy_id(core)?,\n                core.clock_mut().timestamp_ns(),\n            )\n        };\n\n        let orders: Vec<OrderAny> = {\n            let cache_rc = StrategyNative::strategy_core_mut(self).cache_rc();\n            let cache = cache_rc.borrow();\n            updates\n                .iter()\n                .map(|(client_order_id, _, _, _)| {\n                    cache","sourceCodeStart":446,"sourceCodeEnd":482,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/trading/src/strategy/mod.rs#L446-L482","documentation":"`modify_orders` refuses to build a BatchModifyOrders command when the `updates` list is empty. A batch request must contain at least one (order, update) pair; an empty list would produce a meaningless or invalid command for the execution engine. The bail happens before any trader/strategy IDs are resolved.","triggerScenarios":"Calling `strategy.modify_orders(vec![], instrument_id, None, None)` (or an updates slice built by filtering an original list down to zero elements).","commonSituations":"Filtering pending updates before the call (e.g. skipping already-closed orders) so the vec becomes empty; upstream data returning no actionable updates; uninitialized/default vectors passed by mistake.","solutions":["Ensure the updates list is non-empty before calling modify_orders","Guard the call: if updates.is_empty() { return Ok(()); } (skip instead of error)","Check upstream logic that filters/derives the update list so it cannot drop all entries","If an empty batch is legitimately a no-op, handle it at the call site rather than invoking the API"],"exampleFix":"// before\nstrategy.modify_orders(updates, instrument_id, None, None).await?;\n// after\nif !updates.is_empty() {\n    strategy.modify_orders(updates, instrument_id, None, None).await?;\n}","handlingStrategy":"validation","validationCode":"if updates.is_empty() {\n    // no-op or return early; do not call modify_orders\n    return Ok(());\n}","typeGuard":"fn is_non_empty<T>(items: &[T]) -> bool { !items.is_empty() }","tryCatchPattern":null,"preventionTips":["Guard empty batches at the call site","Be careful with filter chains that can drain the update list to zero","Log/skip no-op batches instead of invoking the API"],"tags":["validation","batch-orders","empty-input"],"backgroundTag":"empty-required-field","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}