nautechsystems/nautilus_trader · error
Batch cancel failed: {error_msg}
Error message
Batch cancel failed: {error_msg} What it means
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.
Source
Thrown at crates/adapters/kraken/src/http/futures/client.rs:2357
/// # Returns
/// The total number of successfully cancelled orders.
pub async fn cancel_orders_batch(
&self,
venue_order_ids: Vec<VenueOrderId>,
) -> anyhow::Result<usize> {
if venue_order_ids.is_empty() {
return Ok(0);
}
let mut total_cancelled = 0;
for chunk in venue_order_ids.chunks(BATCH_CANCEL_LIMIT) {
let order_ids: Vec<String> = chunk.iter().map(|id| id.to_string()).collect();
let response = self.inner.cancel_orders_batch(order_ids).await?;
if response.result != KrakenApiResult::Success {
let error_msg = response.error.as_deref().unwrap_or("Unknown error");
anyhow::bail!("Batch cancel failed: {error_msg}");
}
let success_count = response
.batch_status
.iter()
.filter(|s| {
s.status == Some(KrakenSendStatus::Cancelled)
|| s.cancel_status
.as_ref()
.is_some_and(|cs| cs.status == KrakenSendStatus::Cancelled)
})
.count();
total_cancelled += success_count;
}
Ok(total_cancelled)
}View on GitHub (pinned to 18893faf8b)
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.
Example fix
// before: one chunk failure aborts everything
client.batch_cancel_orders(instrument_id, &all_ids).await?;
// after: per-order fallback on chunk failure
match client.batch_cancel_orders(instrument_id, &all_ids).await {
Ok(()) => {}
Err(e) => { for id in &all_ids { let _ = client.cancel_order(instrument_id, None, Some(*id)).await; } }
} Defensive patterns
Strategy: fallback
Validate before calling
assert!(ids.len() <= 100, "Kraken batch cancel limit exceeded"); assert!(ids.iter().all(|i| open_orders.contains(i)), "batch contains non-open order ids");
Type guard
fn batch_is_valid(ids: &[VenueOrderId], open: &HashSet<VenueOrderId>) -> bool {
!ids.is_empty() && ids.len() <= 100 && ids.iter().all(|i| open.contains(i))
} Try / catch
match client.batch_cancel_orders(instrument_id, &ids).await {
Err(e) => {
log::warn!("batch cancel failed ({e}); falling back to per-order cancels");
for id in &ids { let _ = client.cancel_order(instrument_id, Some(*id), None).await; }
}
Ok(_) => {}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Order cancellation failed: {status}
- cancel algo order failed
- cancel algo orders failed
- cancel advance algo orders failed
- failed to batch cancel orders
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/98360006787eef58.
Report an issue: GitHub.