nautechsystems/nautilus_trader · error

Order modification rejected: {reason}

Error message

Order modification rejected: {reason}

What it means

Raised by modify_order when BitMEX accepts the amend request but returns an order whose ordStatus is 'Rejected'. The adapter maps this venue-level rejection into a Rust error, using ordRejReason if present (otherwise 'No reason provided'). The request technically succeeded at HTTP level but the modification was refused by the venue.

Source

Thrown at crates/adapters/bitmex/src/http/client.rs:2000

        }

        if let Some(price) = price {
            params.price(price.as_f64());
        }

        if let Some(trigger_price) = trigger_price {
            params.stop_px(trigger_price.as_f64());
        }

        let params = params.build().map_err(|e| anyhow::anyhow!(e))?;

        let order: BitmexOrder = self.inner.amend_order_response(params).await?;

        if order.ord_status == Some(BitmexOrderStatus::Rejected) {
            let reason = order
                .ord_rej_reason
                .map_or_else(|| "No reason provided".to_string(), |r| r.to_string());
            anyhow::bail!("Order modification rejected: {reason}");
        }

        let instrument = self.instrument_from_cache(instrument_id.symbol.inner())?;
        let ts_init = self.generate_ts_init();

        parse_order_status_report(&order, &instrument, &self.order_type_cache, ts_init)
    }

    /// Query a single order by client order ID or venue order ID.
    ///
    /// # Errors
    ///
    /// Returns an error if:
    /// - Credentials are missing.
    /// - The request fails.
    /// - The API returns an error.
    pub async fn query_order(
        &self,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the returned reason string in the error message to identify the venue's rejection cause
  2. Re-query the order status to confirm its current state before retrying the amend
  3. Validate the new quantity/price against the instrument's limits before calling modify_order
  4. Handle the race where the order has already filled — treat as a no-op or cancel flow

Example fix

// before
let report = client.modify_order(instrument_id, None, Some(vid), Some(new_qty), None, None).await?;
// after
let current = client.request_order_status_report(instrument_id, None, Some(vid)).await?;
if current.order_status != OrderStatus::Accepted { return Ok(current); }
let report = client.modify_order(instrument_id, None, Some(vid), Some(new_qty), None, None).await?;
Defensive patterns

Strategy: try-catch

Validate before calling

let current = client.request_order_status_report(instrument_id, client_order_id.clone(), venue_order_id.clone()).await?;
if current.order_status == OrderStatus::Filled || current.order_status == OrderStatus::Canceled {
    return Ok(current); // nothing to amend
}

Type guard

fn amendable(report: &OrderStatusReport) -> bool {
    matches!(report.order_status, OrderStatus::Accepted | OrderStatus::PartiallyFilled)
}

Try / catch

match client.modify_order(...).await {
    Ok(report) => { /* handle */ }
    Err(e) if e.to_string().starts_with("Order modification rejected:") => {
        let reason = e.to_string();
        // re-query order state and decide: retry, cancel, or alert
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Amending an order in a way BitMEX rejects: modifying a filled/canceled order, changing quantity/price to invalid values, or amending during certain market states. Any amend response with ordStatus==Rejected triggers it.

Common situations: Race conditions where the order fills just before the amend arrives; price/qty outside instrument limits; amending orders that are already terminal.

Related errors


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