nautechsystems/nautilus_trader · error · BinanceSpotHttpError

venue_order_id required for modify

Error message

venue_order_id required for modify

What it means

On the HTTP modify path, Binance Spot modification is a cancel-replace keyed by the venue's numeric order ID; when the `ModifyOrder` command carries `venue_order_id = None` the adapter cannot build the request and short-circuits with `BinanceSpotHttpError::ValidationError("venue_order_id required for modify")`. This is a local failure (no request is sent), classified by `is_local_command_failure`, so it surfaces to the strategy as an `OrderModifyRejected` event with reason 'modify-order-error: venue_order_id required for modify'.

Source

Thrown at crates/adapters/binance/src/spot/execution.rs:1690

            self.spawn_task("modify_order_http", async move {
                let result = match command.venue_order_id {
                    Some(venue_order_id) => {
                        http_client
                            .modify_order(
                                account_id,
                                command.instrument_id,
                                venue_order_id,
                                command.client_order_id,
                                order_side,
                                order_type,
                                quantity,
                                time_in_force,
                                command.price,
                                use_gtd,
                            )
                            .await
                    }
                    None => Err(anyhow::anyhow!(BinanceSpotHttpError::ValidationError(
                        "venue_order_id required for modify".to_string()
                    ))),
                };

                match result {
                    Ok(report) => {
                        let ts_now = clock.get_time_ns();
                        let updated_event = OrderUpdated::new(
                            trader_id,
                            command.strategy_id,
                            command.instrument_id,
                            command.client_order_id,
                            report.quantity,
                            UUID4::new(),
                            ts_now,
                            ts_now,
                            false,
                            Some(report.venue_order_id),

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Wait for the order to be acknowledged (OrderSubmitted → OrderAccepted/OrderUpdated with a venue_order_id) before sending ModifyOrder
  2. Populate `venue_order_id` on the ModifyOrder command (look it up from the cached order) when building the command yourself
  3. Enable the WS trading transport, whose cancel-replace params can fall back to the client order ID when the venue ID is absent

Example fix

# before
modify = ModifyOrder(
    trader_id=self.trader_id,
    strategy_id=self.id,
    instrument_id=order.instrument_id,
    client_order_id=order.client_order_id,
    venue_order_id=None,  # rejected: HTTP modify keys on the venue ID
    quantity=new_qty,
    price=new_price,
    command_id=UUID4(),
    ts_init=self.clock.timestamp_ns(),
)

# after
modify = ModifyOrder(
    trader_id=self.trader_id,
    strategy_id=self.id,
    instrument_id=order.instrument_id,
    client_order_id=order.client_order_id,
    venue_order_id=order.venue_order_id,  # assigned after venue acknowledgment
    quantity=new_qty,
    price=new_price,
    command_id=UUID4(),
    ts_init=self.clock.timestamp_ns(),
)
Defensive patterns

Strategy: validation

Validate before calling

# Python: guard before submitting the modify (HTTP path requires the venue ID)
order = self.cache.order(client_order_id)
if order is None:
    self.log.error(f"Order {client_order_id} not in cache; cannot modify")
    return
if order.venue_order_id is None:
    self.log.info(
        f"Order {client_order_id} not yet acknowledged by venue; deferring modify"
    )
    return  # retry after the next OrderAccepted/OrderUpdated event
self.request(modify_command)

Type guard

# Python
def is_modifiable_on_venue(order) -> bool:
    """True when the order carries a venue-assigned ID (required for HTTP modify)."""
    return order.venue_order_id is not None and order.is_open

Try / catch

# Python: the failure arrives as an event, not an exception — handle the rejection
self.msgbus.subscribe("events.order.modify_rejected", handler)

def handler(event):
    if "venue_order_id required for modify" in str(event.reason):
        # order not yet acknowledged; re-queue the modify for after acknowledgment
        ...

Prevention

When it happens

Trigger: Calling `modify_order` while WS trading is not active with a `ModifyOrder` whose `venue_order_id` is None — typically because the strategy constructed the command identifying the order only by `client_order_id`, or because the order has not yet been acknowledged by Binance (no venue ID assigned yet).

Common situations: Modifying immediately after submitting (before OrderAccepted/Updated carries the venue_order_id); replaying or simulating live strategies where ModifyOrder objects were created without venue IDs; strategies ported from venues whose amend API keys on client order ID instead of venue order ID.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16). Data as JSON: /api/errors/f6a4daa01290d58c. Report an issue: GitHub.