nautechsystems/nautilus_trader · error

Either client_order_id or venue_order_id must be provided fo

Error message

Either client_order_id or venue_order_id must be provided for each order

What it means

In the batch cancel loop, each per-order entry must carry either the venue order ID or the client order ID. When both Options are None for an entry, the adapter bails because the individual cancel entry cannot be built for Bybit.

Source

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

        }

        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());
            } else if let Some(client_order_id) = client_order_id {
                cancel_entry.order_link_id(client_order_id.to_string());
            } else {
                anyhow::bail!(
                    "Either client_order_id or venue_order_id must be provided for each order"
                );
            }

            cancel_entries.push(cancel_entry.build().build_anyhow()?);
        }

        let chunk_limit = batch_endpoint_limit(product_type).min(batch_send_limit(product_type));
        for chunk in cancel_entries.chunks(chunk_limit) {
            let mut params = BybitBatchCancelOrderParamsBuilder::default();
            params.category(product_type);
            params.request(chunk.to_vec());

            let params = params.build().build_anyhow()?;
            let body = serde_json::to_vec(&params)?;

            let _response: BybitPlaceOrderResponse = self
                .inner

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure every batch element has at least one populated identifier
  2. Filter out orders with no identifier and cancel them via a different path (e.g. cancel-all-orders by symbol)
  3. Look up the venue order ID from the cache before batching

Example fix

// before
client_ids.push(None); venue_ids.push(None); // unpadded placeholder
// after
if client_id.is_none() && venue_id.is_none() { continue; } // or resolve from cache first
Defensive patterns

Strategy: validation

Validate before calling

for (c, v) in client_order_ids.iter().zip(venue_order_ids.iter()) {
    anyhow::ensure!(c.is_some() || v.is_some(), "each order needs an identifier");
}

Type guard

fn entry_identifiable(c: &Option<ClientOrderId>, v: &Option<VenueOrderId>) -> bool { c.is_some() || v.is_some() }

Prevention

When it happens

Trigger: Calling batch_cancel_all_orders with one or more positions in the parallel vectors where both client_order_ids[i] and venue_order_ids[i] are None.

Common situations: Batching cancels for orders whose venue acknowledgement never arrived and whose client ID was not stored; placeholder None entries used to pad the vectors to equal length.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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