nautechsystems/nautilus_trader · error

Modify order failed: {e}

Error message

Modify order failed: {e}

What it means

The modify_order command is executed asynchronously via a spawned task; if the underlying ws_client modify-order request to Deribit fails, the error is logged with both order and client order IDs and re-raised as 'Modify order failed: {e}'. Note modify_order itself returns Ok(()) immediately — the failure surfaces in the spawned task.

Source

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

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

        Ok(())
    }

    fn cancel_order(&self, cmd: CancelOrder) -> anyhow::Result<()> {
        let ws_client = self.ws_client.clone();

        // Extract venue order ID (Deribit's order_id)
        let order_id = match cmd.venue_order_id.as_ref() {
            Some(venue_order_id) => venue_order_id.to_string(),
            None => {
                log::warn!(
                    "Cannot cancel order {} - no venue_order_id",
                    cmd.client_order_id
                );

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the inner error (logged with order_id/client_order_id) to determine the venue rejection reason
  2. Verify the order is still open on Deribit before modifying (not filled or cancelled)
  3. Confirm the WebSocket connection is alive and authenticated before issuing the modify
  4. Handle Deribit rate limits by spacing out order-management calls

Example fix

// before
if let Err(e) = ws_client.modify_order(order_id, client_order_id, price, size).await {
    anyhow::bail!("Modify order failed: {e}");
}
// after
if let Err(e) = ws_client.modify_order(order_id, client_order_id, price, size).await {
    log::warn!("modify rejected, refreshing order state before retry: {e}");
    let state = query_order_state(order_id).await?;
    if state.is_open() {
        ws_client.modify_order(order_id, client_order_id, price, size).await?;
    }
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Before modifying, confirm the order is still open
let open = live_orders.contains_key(&venue_order_id);
if !open { log::warn!("skip modify: order not open"); return Ok(()); }

Try / catch

match client.modify_order(cmd).await {
    Ok(()) => {} // note: failures surface asynchronously in the spawned task
    Err(e) => log::error!("modify dispatch failed: {e}"),
}
// watch the ModifyOrderRejected event / spawned-task error for the venue reason

Prevention

When it happens

Trigger: Calling modify_order with an order_id/client_order_id that does not exist on the venue, an invalid price/size adjustment, an already-filled or cancelled order, or when Deribit rejects the edit request (auth, rate limit, connection drop).

Common situations: Race where the order is filled/cancelled between submit and modify; stale venue_order_id; modifying an order on a disconnected WebSocket; Deribit rate limiting on order management calls.

Related errors


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