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
- Wait for the order to be acknowledged (OrderSubmitted → OrderAccepted/OrderUpdated with a venue_order_id) before sending ModifyOrder
- Populate `venue_order_id` on the ModifyOrder command (look it up from the cached order) when building the command yourself
- 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
- Only modify orders whose venue_order_id is populated (i.e., after the venue acknowledged the submit)
- Derive ModifyOrder fields from the cached order instead of rebuilding them by hand
- If your strategy amends aggressively right after submit, enable WS trading so the cancel-replace can key on the client order ID
- Unit-test the modify flow against a sandbox where venue IDs are assigned asynchronously
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
- Invalid venue order ID: {id}
- WS modify order failed: {e}
- Conditional orders require a trigger price
- height must be positive, was {self.height}
- Cannot modify order without venue_order_id
AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16).
Data as JSON: /api/errors/f6a4daa01290d58c.
Report an issue: GitHub.