{"record":{"id":"9d5c1b9dad497f88","repo":"nautechsystems/nautilus_trader","slug":"cannot-batch-cancel-orders-for-different-instrumen","errorCode":null,"errorMessage":"Cannot batch cancel orders for different instruments: {} vs {}","messagePattern":"Cannot batch cancel orders for different instruments: (.+?) vs (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/trading/src/strategy/mod.rs","lineNumber":714,"sourceCode":"        // TODO: Snapshot all orders from the cache. See `cancel_order` for the rationale.\n        let orders: Vec<OrderAny> = {\n            let cache_rc = StrategyNative::strategy_core_mut(self).cache_rc();\n            let cache = cache_rc.borrow();\n            client_order_ids\n                .iter()\n                .map(|id| {\n                    cache\n                        .try_order_owned(id)\n                        .map_err(|e| anyhow::anyhow!(\"Cannot cancel order: {e}\"))\n                })\n                .collect::<Result<_, _>>()?\n        };\n\n        let instrument_id = orders[0].instrument_id();\n\n        for order in &orders {\n            if order.instrument_id() != instrument_id {\n                anyhow::bail!(\n                    \"Cannot batch cancel orders for different instruments: {} vs {}\",\n                    instrument_id,\n                    order.instrument_id()\n                );\n            }\n\n            if order.is_emulated() || order.is_active_local() {\n                anyhow::bail!(\"Cannot include emulated or local orders in batch cancel\");\n            }\n        }\n\n        let mut cancels = Vec::with_capacity(orders.len());\n\n        for order in orders {\n            if !self.mark_order_pending_cancel(&order)? {\n                continue;\n            }\n","sourceCodeStart":696,"sourceCodeEnd":732,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/trading/src/strategy/mod.rs#L696-L732","documentation":"All orders named in a batch cancel must belong to the same instrument. Each order's instrument_id is compared to the first order's; any mismatch aborts the batch because a BatchCancelOrders command is venue/instrument-scoped.","triggerScenarios":"Passing client_order_ids resolving to orders on two or more different instruments to `cancel_orders`.","commonSituations":"Cancelling 'all working orders' across symbols in one call; building the ID list from a multi-instrument cache scan; after a symbol change without regenerating the list.","solutions":["Group client_order_ids by instrument_id and issue one cancel_orders call per instrument","Verify the list only contains IDs from a single instrument (e.g. from strategy orders for that instrument)","Use cancel_all_orders(instrument_id) per instrument instead of a mixed batch"],"exampleFix":"// before\nstrategy.cancel_orders(&all_ids, instrument_id, None, None).await?;\n// after\nfor iid in all_instruments {\n    let ids: Vec<ClientOrderId> = all_orders.iter()\n        .filter(|o| o.instrument_id() == iid)\n        .map(|o| o.client_order_id())\n        .collect();\n    if !ids.is_empty() {\n        strategy.cancel_orders(&ids, iid, None, None).await?;\n    }\n}","handlingStrategy":"validation","validationCode":"let resolved: Vec<_> = ids.iter().map(|id| cache.order(id)).collect::<Option<Vec<_>>>().unwrap_or_default();\nlet iid = resolved[0].instrument_id();\nassert!(resolved.iter().all(|o| o.instrument_id() == iid), \"batch cancel spans instruments\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Resolve orders and group by instrument before batching","Track client_order_ids per instrument in strategy state","Use per-instrument cancel_all_orders as a simpler alternative"],"tags":["validation","batch-orders","instrument-mismatch"],"backgroundTag":"invalid-argument-value","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"}