nautechsystems/nautilus_trader · error

Batch cancel limit is {call_limit} orders for {}

Error message

Batch cancel limit is {call_limit} orders for {}

What it means

Bybit caps the number of orders per batch cancel request depending on product type (batch call limit). The adapter enforces this limit client-side and bails if the batch exceeds it, to avoid the venue rejecting the whole request.

Source

Thrown at crates/adapters/bybit/src/http/client.rs:2772

        instrument_ids: Vec<InstrumentId>,
        client_order_ids: Vec<Option<ClientOrderId>>,
        venue_order_ids: Vec<Option<VenueOrderId>>,
    ) -> anyhow::Result<Vec<OrderStatusReport>> {
        if instrument_ids.len() != client_order_ids.len()
            || instrument_ids.len() != venue_order_ids.len()
        {
            anyhow::bail!(
                "instrument_ids, client_order_ids, and venue_order_ids must have the same length"
            );
        }

        if instrument_ids.is_empty() {
            return Ok(Vec::new());
        }

        let call_limit = batch_call_limit(product_type);
        if instrument_ids.len() > call_limit {
            anyhow::bail!(
                "Batch cancel limit is {call_limit} orders for {}",
                product_type.as_str()
            );
        }

        let mut cancel_entries = Vec::new();

        for ((instrument_id, client_order_id), venue_order_id) in instrument_ids
            .iter()
            .zip(client_order_ids.iter())
            .zip(venue_order_ids.iter())
        {
            let bybit_symbol = BybitSymbol::new(instrument_id.symbol.as_str())?;
            let mut cancel_entry = BybitBatchCancelOrderEntryBuilder::default();
            cancel_entry.symbol(bybit_symbol.raw_symbol().to_string());

            if let Some(venue_order_id) = venue_order_id {
                cancel_entry.order_id(venue_order_id.to_string());

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Split the batch into chunks of at most the product-type call limit and issue multiple requests
  2. Check instrument_ids.len() against the limit before calling and chunk accordingly
  3. Handle cancellation in smaller routine batches instead of one bulk call

Example fix

// before
client.batch_cancel_all_orders(product_type, symbol, ids, cids, vids).await?;
// after
for chunk in ids.chunks(call_limit) { /* chunk all parallel vectors */ ... }
Defensive patterns

Strategy: validation

Validate before calling

let call_limit = bybit_batch_call_limit(product_type);
anyhow::ensure!(instrument_ids.len() <= call_limit, "batch of {} exceeds limit {}", instrument_ids.len(), call_limit);

Prevention

When it happens

Trigger: Calling batch_cancel_all_orders with more orders in the batch than batch_call_limit(product_type) allows for that product type.

Common situations: Cancelling a large open-order book in one call during risk-off flows; linear product types with larger limits used where the spot limit applies (or vice versa).

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/2a2944e2b5d6cd05. Report an issue: GitHub.