nautechsystems/nautilus_trader · error
Batch cancel limit is {endpoint_limit} orders for {product_t
Error message
Batch cancel limit is {endpoint_limit} orders for {product_type} What it means
A Bybit batch cancel request exceeded the venue's per-endpoint batch limit for the given product type (spot vs linear/inverse derivatives have different limits, e.g. linear typically caps batch cancels at 10). The request is rejected client-side before being sent.
Source
Thrown at crates/adapters/bybit/src/http/client.rs:2841
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 endpoint_limit = batch_endpoint_limit(product_type);
if instrument_ids.len() > endpoint_limit {
anyhow::bail!(
"Batch cancel limit is {endpoint_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 d1527c24af)
Solutions
- Chunk the cancels into batches of at most batch_endpoint_limit(product_type) orders per request
- Reduce the number of instruments targeted per batch cancel call
- Fall back to individual cancel requests for the remainder when chunking is awkward
Example fix
// before
let reports = client.batch_cancel(instrument_ids).await?;
// after
let limit = 10; // batch_endpoint_limit(product_type)
for chunk in instrument_ids.chunks(limit) {
let reports = client.batch_cancel(chunk.to_vec()).await?;
} Defensive patterns
Strategy: validation
Validate before calling
const LIMIT: usize = 10; // match batch_endpoint_limit(product_type)
if instrument_ids.len() > LIMIT {
anyhow::bail!("batch cancel of {} exceeds Bybit limit {LIMIT}; chunk the request", instrument_ids.len());
} Prevention
- Always chunk batch cancels by the venue's documented limit
- Cache the per-product-type limit instead of assuming one global value
- Log batch sizes during high-volatility cancel storms to catch approaching limits
When it happens
Trigger: Calling the batch cancel path (cancel_all via batch endpoint or batch_cancel_orders) on the Bybit HTTP client with more instrument_ids/orders than batch_endpoint_limit(product_type) allows.
Common situations: A strategy firing many cancels across instruments during a volatility spike gets bucketed into one oversized batch; migrating from an adapter/version with a higher limit; spot limits applied to derivatives workflows.
Related errors
- Batch cancel limit is {call_limit} orders for {}
- Bybit execution shutdown failed: {}
- Timeout waiting for account {account_id} to be registered af
- instrument_ids, client_order_ids, and venue_order_ids must h
- Either client_order_id or venue_order_id must be provided fo
AI-assisted analysis of nautechsystems/nautilus_trader@d1527c24af (2026-08-27).
Data as JSON: /api/errors/89dea5ae496148e9.
Report an issue: GitHub.