nautechsystems/nautilus_trader · error

Unsupported order side {}; only Buy and Sell are supported

Error message

Unsupported order side {}; only Buy and Sell are supported

What it means

prepare_swap only supports OrderSide::Buy and OrderSide::Sell; any other side value is rejected. A swap always moves value in one direction, so both a side must be present and it must be one of the two directional values.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:1559

    /// Validates a submit-order command against the configured policy and builds the swap plan.
    ///
    /// Local checks run first: pool resolution, order semantics, allowlists, amount and
    /// slippage limits, and the quote derived from the live pool profiler. Infrastructure
    /// readiness (connection, in-flight slot, durable store, signer) follows. Chain state is
    /// verified in the spawned task before signing.
    fn prepare_swap(&self, cmd: &SubmitOrder, order: &OrderAny) -> anyhow::Result<SwapPlan> {
        let instrument_id = order.instrument_id();
        let pool = self.resolve_pool(&instrument_id)?;

        if order.order_type() != OrderType::Market {
            anyhow::bail!(
                "Unsupported order type {}; only Market is supported",
                order.order_type()
            );
        }

        if !matches!(order.order_side(), OrderSide::Buy | OrderSide::Sell) {
            anyhow::bail!(
                "Unsupported order side {}; only Buy and Sell are supported",
                order.order_side()
            );
        }

        if order.is_quote_quantity() {
            anyhow::bail!(
                "Quote-denominated quantities are not supported; quantity must be denominated in the base token"
            );
        }

        let fee = pool
            .fee
            .ok_or_else(|| anyhow::anyhow!("Pool {instrument_id} has no fee tier"))?;
        let fee = U24::try_from(fee)
            .map_err(|_| anyhow::anyhow!("Pool {instrument_id} fee {fee} exceeds uint24"))?;

        let base_token = pool.get_base_token();

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Set order_side explicitly to OrderSide::Buy or OrderSide::Sell before submitting.
  2. Validate/normalize the side when ingesting orders from external systems before they reach submit_order.

Example fix

// before
let order = OrderAny::default(); // side unset
client.submit_order(cmd, &order)?;
// after
let mut order = OrderAny::default();
order.set_order_side(OrderSide::Buy);
client.submit_order(cmd, &order)?;
Defensive patterns

Strategy: validation

Validate before calling

// Rust
if !matches!(order.order_side(), OrderSide::Buy | OrderSide::Sell) {
    return Err(anyhow::anyhow!("order side must be Buy or Sell"));
}

Prevention

When it happens

Trigger: submit_order called with an order whose order_side() is neither Buy nor Sell (e.g. an uninitialized/default side, or a side variant from another venue vocabulary).

Common situations: Constructing orders programmatically and forgetting to set the side; deserializing orders from an external system where the side field maps to a different variant; copying order-construction code from a venue with different side semantics.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


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