nautechsystems/nautilus_trader · error

Cancel order failed: {e}

Error message

Cancel order failed: {e}

What it means

The cancel_order command runs in a spawned task; if the ws_client cancel-order request to Deribit fails, the error is logged with order_id and client_order_id and re-raised as 'Cancel order failed: {e}'. Like modify_order, cancel_order returns Ok(()) immediately; the failure is observable only in the spawned task's error path.

Source

Thrown at crates/adapters/deribit/src/execution.rs:973

        log::debug!("Canceling order: order_id={order_id}, client_order_id={client_order_id}");

        // Spawn async task to send cancel via WebSocket
        self.spawn_task("cancel_order", async move {
            if let Err(e) = ws_client
                .cancel_order(
                    &order_id,
                    client_order_id,
                    trader_id,
                    strategy_id,
                    instrument_id,
                )
                .await
            {
                log::error!(
                    "Cancel order failed: order_id={order_id}, client_order_id={client_order_id}, error={e}"
                );
                anyhow::bail!("Cancel order failed: {e}");
            }
            Ok(())
        });

        Ok(())
    }

    fn cancel_all_orders(&self, cmd: CancelAllOrders) -> anyhow::Result<()> {
        let instrument_id = cmd.instrument_id;

        // Without a side filter, use efficient bulk cancel via Deribit API
        let Some(order_side) = cmd.order_side else {
            log::debug!(
                "Cancelling all orders: instrument={instrument_id}, order_side=None (bulk)"
            );

            let ws_client = self.ws_client.clone();
            self.spawn_task("cancel_all_orders", async move {

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the logged inner error for the venue rejection reason (e.g. unknown order vs connection failure)
  2. Verify the order is still open before cancelling; treat 'already filled/cancelled' rejections as benign
  3. Check WebSocket connectivity and re-authenticate if the session dropped
  4. Retry the cancel once connectivity is restored, or use cancel_all_orders as a safety net

Example fix

// before
if let Err(e) = ws_client.cancel_order(order_id, client_order_id).await {
    anyhow::bail!("Cancel order failed: {e}");
}
// after
if let Err(e) = ws_client.cancel_order(order_id, client_order_id).await {
    if !e.to_string().contains("not found") && !e.to_string().contains("already") {
        anyhow::bail!("Cancel order failed: {e}");
    }
    log::info!("order already inactive on venue: {order_id}");
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Before cancelling, confirm the order is still live
if !open_orders.contains(&venue_order_id) {
    log::info!("skip cancel: order not open");
    return Ok(());
}

Try / catch

match client.cancel_order(cmd).await {
    Ok(()) => {}, // failure surfaces asynchronously in the spawned task
    Err(e) => log::error!("cancel dispatch failed: {e}"),
}
// on 'Cancel order failed' in task logs, treat already-filled/cancelled as benign

Prevention

When it happens

Trigger: Calling cancel_order for an order_id/client_order_id unknown to Deribit, an already-filled or cancelled order, or when the request fails due to auth, rate limits, or a dropped WebSocket connection.

Common situations: Cancelling an order that was just filled (common race in fast markets); duplicate cancel attempts; stale order IDs after reconnect; WebSocket disconnection mid-request.

Related errors


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