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
- Check the inner error (logged with order_id/client_order_id) to determine the venue rejection reason
- Verify the order is still open on Deribit before modifying (not filled or cancelled)
- Confirm the WebSocket connection is alive and authenticated before issuing the modify
- 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
- Track order state and only modify orders known to be open on the venue
- Use client_order_id consistently so rejections are traceable
- Throttle order-management calls to stay under Deribit rate limits
- Re-check connectivity after any WebSocket drop before issuing modifies
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
- Cancel order failed: {e}
- Cancel all orders failed: {e}
- InstrumentState channel requires kind and currency parameter
- errors joined with "; " (aggregated disconnect errors)
- errors joined with "; " (aggregated disconnect errors)
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/1cd846fc31228cb2.
Report an issue: GitHub.