{"record":{"id":"98360006787eef58","repo":"nautechsystems/nautilus_trader","slug":"batch-cancel-failed-error-msg","errorCode":null,"errorMessage":"Batch cancel failed: {error_msg}","messagePattern":"Batch cancel failed: (.+?)","errorType":"http","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/kraken/src/http/futures/client.rs","lineNumber":2357,"sourceCode":"    /// # Returns\n    /// The total number of successfully cancelled orders.\n    pub async fn cancel_orders_batch(\n        &self,\n        venue_order_ids: Vec<VenueOrderId>,\n    ) -> anyhow::Result<usize> {\n        if venue_order_ids.is_empty() {\n            return Ok(0);\n        }\n\n        let mut total_cancelled = 0;\n\n        for chunk in venue_order_ids.chunks(BATCH_CANCEL_LIMIT) {\n            let order_ids: Vec<String> = chunk.iter().map(|id| id.to_string()).collect();\n            let response = self.inner.cancel_orders_batch(order_ids).await?;\n\n            if response.result != KrakenApiResult::Success {\n                let error_msg = response.error.as_deref().unwrap_or(\"Unknown error\");\n                anyhow::bail!(\"Batch cancel failed: {error_msg}\");\n            }\n\n            let success_count = response\n                .batch_status\n                .iter()\n                .filter(|s| {\n                    s.status == Some(KrakenSendStatus::Cancelled)\n                        || s.cancel_status\n                            .as_ref()\n                            .is_some_and(|cs| cs.status == KrakenSendStatus::Cancelled)\n                })\n                .count();\n\n            total_cancelled += success_count;\n        }\n\n        Ok(total_cancelled)\n    }","sourceCodeStart":2339,"sourceCodeEnd":2375,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/kraken/src/http/futures/client.rs#L2339-L2375","documentation":"Batch cancel (cancel multiple orders at once, in chunks of BATCH_CANCEL_LIMIT) returned result != Success; the error field text from Kraken Futures is embedded in the message. The whole chunk's batch request failed at the venue.","triggerScenarios":"Calling the batch cancel with >100 ids (beyond Kraken's limit) or an invalid id in the list; venue rejects the whole batch for auth, rate limit, or one malformed order_id; API result flag not 'success' in the batch response.","commonSituations":"Mass-flatten logic cancelling many open orders at once; stale id lists from a previous session; hitting Kraken batch-cancel rate limits during volatile markets.","solutions":["Read the embedded error_msg to identify whether it is a rate limit, auth, or per-order validation problem.","Reduce batch size / pace requests if the error indicates rate limiting; the client already chunks by BATCH_CANCEL_LIMIT but back off on failures.","Validate every venue_order_id in the list corresponds to an open order before batching.","Fall back to per-order cancels for the chunk and collect per-order outcomes so one bad id doesn't abort all."],"exampleFix":"// before: one chunk failure aborts everything\nclient.batch_cancel_orders(instrument_id, &all_ids).await?;\n\n// after: per-order fallback on chunk failure\nmatch client.batch_cancel_orders(instrument_id, &all_ids).await {\n    Ok(()) => {}\n    Err(e) => { for id in &all_ids { let _ = client.cancel_order(instrument_id, None, Some(*id)).await; } }\n}","handlingStrategy":"fallback","validationCode":"assert!(ids.len() <= 100, \"Kraken batch cancel limit exceeded\");\nassert!(ids.iter().all(|i| open_orders.contains(i)), \"batch contains non-open order ids\");","typeGuard":"fn batch_is_valid(ids: &[VenueOrderId], open: &HashSet<VenueOrderId>) -> bool {\n    !ids.is_empty() && ids.len() <= 100 && ids.iter().all(|i| open.contains(i))\n}","tryCatchPattern":"match client.batch_cancel_orders(instrument_id, &ids).await {\n    Err(e) => {\n        log::warn!(\"batch cancel failed ({e}); falling back to per-order cancels\");\n        for id in &ids { let _ = client.cancel_order(instrument_id, Some(*id), None).await; }\n    }\n    Ok(_) => {}\n}","preventionTips":["Respect Kraken batch size and rate limits; add backoff between chunks","Refresh the open-order list immediately before mass cancels","Fall back to per-order cancels so a single bad id doesn't abort the batch"],"tags":["batch-cancel","venue-rejection","kraken-futures","http"],"backgroundTag":"api-error-response","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"}