nautechsystems/nautilus_trader · error

Either client_order_id or venue_order_id must be provided

Error message

Either client_order_id or venue_order_id must be provided

What it means

cancel_order on Kraken Futures requires at least one order identifier. Both venue_order_id and client_order_id were None, so the client cannot tell Kraken which order to cancel and bails before making the request.

Source

Thrown at crates/adapters/kraken/src/http/futures/client.rs:2319

    /// - Neither client_order_id nor venue_order_id is provided.
    /// - The request fails.
    /// - The order cancellation is rejected.
    pub async fn cancel_order(
        &self,
        _account_id: AccountId,
        instrument_id: InstrumentId,
        client_order_id: Option<ClientOrderId>,
        venue_order_id: Option<VenueOrderId>,
    ) -> anyhow::Result<()> {
        let _ = self
            .get_cached_instrument(&instrument_id.symbol.inner())
            .ok_or_else(|| InstrumentLookupError::not_found(instrument_id))?;

        let order_id = venue_order_id.as_ref().map(|id| id.to_string());
        let cli_ord_id = client_order_id.as_ref().map(truncate_cl_ord_id);

        if order_id.is_none() && cli_ord_id.is_none() {
            anyhow::bail!("Either client_order_id or venue_order_id must be provided");
        }

        let response = self.inner.cancel_order(order_id, cli_ord_id).await?;

        if response.result != KrakenApiResult::Success {
            let status = &response.cancel_status.status;
            anyhow::bail!("Order cancellation failed: {status}");
        }

        Ok(())
    }

    /// Cancels multiple orders on the Kraken Futures exchange.
    ///
    /// Automatically chunks requests into batches of 50 orders.
    ///
    /// # Parameters
    /// - `venue_order_ids` - List of venue order IDs to cancel.

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Pass at least one identifier: provide the venue_order_id from the order status report, or the client_order_id used at submit.
  2. If the order was submitted by your strategy, use ClientOrderId as it is truncated and sent via cli_ord_id.
  3. Look up the order in your cache (order registry) to recover the venue_order_id before cancelling.
  4. Add a caller-side check that at least one id is Some before invoking cancel_order.

Example fix

// before
client.cancel_order(instrument_id, None, None).await?;

// after
client.cancel_order(instrument_id, Some(client_order_id), None).await?;
Defensive patterns

Strategy: validation

Validate before calling

if venue_order_id.is_none() && client_order_id.is_none() {
    return Err("cancel_order requires venue_order_id or client_order_id");
}
client.cancel_order(instrument_id, venue_order_id, client_order_id).await?;

Type guard

fn is_cancellable(venue: Option<&VenueOrderId>, client: Option<&ClientOrderId>) -> bool {
    venue.is_some() || client.is_some()
}

Try / catch

match client.cancel_order(instrument_id, vid, cid).await {
    Err(e) if e.to_string().contains("Either client_order_id or venue_order_id") => log::error!("no order id supplied for cancel"),
    Err(e) => return Err(e),
    Ok(_) => {}
}

Prevention

When it happens

Trigger: Calling cancel_order passing neither a venue_order_id nor a client_order_id (both None / both omitted), e.g. cancelling from a partially reconciled order state where neither identifier was stored.

Common situations: Strategy code holding an order ref that was never populated after submit; deserialization or event handling that dropped the client_order_id; calling the raw HTTP client directly without passing an id.

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/97a8e76584f47186. Report an issue: GitHub.