nautechsystems/nautilus_trader · warning

Unsupported SBE order side: {side}

Error message

Unsupported SBE order side: {side}

What it means

map_side converts the SBE order-side enum into the crate's BinanceSide and bails on any variant other than Buy or Sell. The decoded payload carried an order side the adapter does not model — typically the SBE NULL_VALUE sentinel or a variant added by a schema update.

Source

Thrown at crates/adapters/binance/src/spot/websocket/trading/decode_sbe.rs:425

fn map_order_status(os: order_status::OrderStatus) -> BinanceOrderStatus {
    match os {
        order_status::OrderStatus::New => BinanceOrderStatus::New,
        order_status::OrderStatus::PartiallyFilled => BinanceOrderStatus::PartiallyFilled,
        order_status::OrderStatus::Filled => BinanceOrderStatus::Filled,
        order_status::OrderStatus::Canceled => BinanceOrderStatus::Canceled,
        order_status::OrderStatus::PendingCancel => BinanceOrderStatus::PendingCancel,
        order_status::OrderStatus::Rejected => BinanceOrderStatus::Rejected,
        order_status::OrderStatus::Expired => BinanceOrderStatus::Expired,
        order_status::OrderStatus::ExpiredInMatch => BinanceOrderStatus::ExpiredInMatch,
        _ => BinanceOrderStatus::Unknown,
    }
}

fn map_side(side: order_side::OrderSide) -> anyhow::Result<BinanceSide> {
    match side {
        order_side::OrderSide::Buy => Ok(BinanceSide::Buy),
        order_side::OrderSide::Sell => Ok(BinanceSide::Sell),
        _ => anyhow::bail!("Unsupported SBE order side: {side}"),
    }
}

fn map_time_in_force(tif: time_in_force::TimeInForce) -> BinanceTimeInForce {
    match tif {
        time_in_force::TimeInForce::Gtc => BinanceTimeInForce::Gtc,
        time_in_force::TimeInForce::Ioc => BinanceTimeInForce::Ioc,
        time_in_force::TimeInForce::Fok => BinanceTimeInForce::Fok,
        _ => BinanceTimeInForce::Unknown,
    }
}

fn map_order_type(ot: order_type::OrderType) -> &'static str {
    match ot {
        order_type::OrderType::Market => "MARKET",
        order_type::OrderType::Limit => "LIMIT",
        order_type::OrderType::StopLoss => "STOP_LOSS",
        order_type::OrderType::StopLossLimit => "STOP_LOSS_LIMIT",

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Update codecs/adapter to map any newly added side variant
  2. Handle NULL_VALUE by treating it as Unknown or skipping the message upstream
  3. Check which message type was decoded — if side is genuinely absent, decode with the correct type
  4. Log the raw discriminant to confirm it is the null sentinel
Defensive patterns

Strategy: try-catch

Try / catch

match decode_execution_report(&payload) {
    Err(e) if e.to_string().starts_with("Unsupported SBE order side") => {
        log::debug!("null/unknown order side; skipping");
    }
    other => other?,
}

Prevention

When it happens

Trigger: Decoding an execution report whose order_side field is the SBE enum's NULL_VALUE/default, or contains a new side variant absent from the generated order_side::OrderSide enum match.

Common situations: Message types where side is not applicable (e.g. cancel acknowledgments) decode with a null side; stale generated codecs after a Binance schema change; zeroed test fixtures.

Related errors


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