nautechsystems/nautilus_trader · error

asset_id must be resolved for unsided cancellation

Error message

asset_id must be resolved for unsided cancellation

What it means

When cancel_all_orders is issued without a side, the Polymarket execution client must know which market (asset_id) to cancel for, since the venue API cancels per token/market. The code expects the asset_id to have been resolved from the command context; if it is None the panic fires.

Source

Thrown at crates/adapters/polymarket/src/execution/cancellations.rs:361

            }
        }

        if side.is_some() && orders.is_empty() {
            return Ok(());
        }

        let clock = self.clock;
        let submitter = self.submitter.clone();
        let emitter = self.emitter.clone();
        let instrument_id = cmd.instrument_id;

        let spawned = self.spawn_task("cancel_all_orders", async move {
            let _cancel_guard = cancel_guard;
            let response = match side {
                None => {
                    let asset_id = asset_id
                        .as_deref()
                        .expect("asset_id must be resolved for unsided cancellation");
                    submitter.cancel_market_orders(asset_id).await
                }
                Some(_) => {
                    let venue_order_ids = orders
                        .iter()
                        .map(|(venue_order_id, _)| venue_order_id.to_string())
                        .collect::<Vec<_>>();

                    let order_id_refs =
                        venue_order_ids.iter().map(String::as_str).collect::<Vec<_>>();
                    submitter.cancel_orders(&order_id_refs).await
                }
            };

            match response {
                Ok(response) => {
                    for (venue_order_id, order) in &orders {
                        let venue_order_id_str = venue_order_id.to_string();

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Pass an instrument_id (or asset_id) to cancel_all_orders so the market can be resolved.
  2. Iterate over open instruments and issue one unsided cancel per market instead of a global cancel.
  3. If a side-specific cancel is acceptable, pass Some(side) so asset_id is not required.

Example fix

// before
exec_client.cancel_all_orders(None, None); // panics: no market context

// after
for instrument_id in open_instrument_ids {
    exec_client.cancel_all_orders(Some(instrument_id), None);
}
Defensive patterns

Strategy: validation

Validate before calling

# before calling the execution client
if instrument_id is None and asset_id is None:
    raise ValueError("cancel_all_orders requires an instrument_id/asset_id when side is None")
exec_client.cancel_all_orders(instrument_id, None)

Try / catch

try:
    exec_client.cancel_all_orders(instrument_id, None)
except Exception as e:
    self.log.error(f"cancel-all failed for {instrument_id}: {e}")

Prevention

When it happens

Trigger: Submitting a CancelAllOrders command with side=None and no instrument_id/token resolvable to a Polymarket asset_id — e.g. a global cancel-all with no market context.

Common situations: Calling cancel_all_orders() without an instrument_id from a strategy running on multiple markets; UI/dashboard issuing a blanket 'flatten all' cancel; instrument_id not registered so asset_id lookup yielded None.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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