nautechsystems/nautilus_trader · warning

Skipping execution without side: {:?}

Error message

Skipping execution without side: {:?}

What it means

parse_fill_report requires a side to map the execution onto an OrderSide; an execution record with side == None is rejected with this bail because a fill cannot be attributed to buy/sell without it. BitMEX occasionally emits execution rows (funding, adjustments, some liquidation entries) that carry no side.

Source

Thrown at crates/adapters/bitmex/src/http/parse.rs:1109

    // Additional check: skip executions without order_id (likely funding/settlement)
    let order_id = exec.order_id.ok_or_else(|| {
        anyhow::anyhow!("Skipping execution without order_id: {:?}", exec.exec_type)
    })?;

    let account_id = bitmex_account_id(exec.account);
    let instrument_id = instrument.id();
    let venue_order_id = VenueOrderId::new(order_id.to_string());
    // trd_match_id might be missing for some execution types, use exec_id as fallback
    let trade_id = TradeId::new(
        exec.trd_match_id
            .or(Some(exec.exec_id))
            .ok_or_else(|| anyhow::anyhow!("Fill missing both trd_match_id and exec_id"))?
            .to_string(),
    );
    // Skip executions without side (likely not trades)
    let Some(side) = exec.side else {
        anyhow::bail!("Skipping execution without side: {:?}", exec.exec_type);
    };
    let order_side = OrderSide::from(side);
    let last_qty = parse_signed_contracts_quantity(exec.last_qty, instrument);
    let last_px = Price::new(exec.last_px, instrument.price_precision());

    // Map BitMEX currency to standard currency code
    let settlement_currency_str = exec.settl_currency.unwrap_or(Ustr::from("XBT")).as_str();
    let mapped_currency = map_bitmex_currency(settlement_currency_str);
    let currency = get_currency(&mapped_currency);
    let commission = Money::new(exec.commission.unwrap_or(0.0), currency);
    let liquidity_side = parse_liquidity_side(&exec.last_liquidity_ind);
    let client_order_id = exec.cl_ord_id.map(ClientOrderId::new);
    let venue_position_id = None; // Not applicable on BitMEX
    let ts_event = exec.transact_time.map_or(ts_init, UnixNanos::from);

    Ok(FillReport::new(
        account_id,
        instrument_id,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Skip executions where exec.side is None before calling parse_fill_report
  2. Log the exec_id of side-less executions and verify against BitMEX's dashboard whether they represent real fills
  3. Re-fetch the execution via /execution/tradeHistory, which usually populates side for genuine trades
  4. If side is genuinely absent for a known trade, infer it from order side or position effect in surrounding records rather than guessing inside the parser

Example fix

// before
let fill = parse_fill_report(&exec, &instrument, ts_init)?;
// after
let Some(side) = exec.side else {
    tracing::warn!("skipping execution {} without side", exec.exec_id);
    continue;
};
let fill = parse_fill_report(&exec, &instrument, ts_init)?;
Defensive patterns

Strategy: validation

Validate before calling

fn parseable_fill(exec: &BitmexExecution) -> bool {
    matches!(exec.exec_type, BitmexExecType::Trade) && exec.side.is_some()
}
// only call parse_fill_report when parseable_fill(&exec)

Type guard

fn side_of(exec: &BitmexExecution) -> Option<BitmexSide> {
    exec.side
}

Try / catch

match parse_fill_report(exec, instrument, ts_init) {
    Ok(fill) => fills.push(fill),
    Err(e) if e.to_string().contains("without side") => {
        warn!("exec {} had no side; skipped", exec.exec_id);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: request_fill_reports encountering a Trade-typed execution record whose side field is null, or a directly constructed/test execution without side set.

Common situations: BitMEX returning execution rows with missing side during exchange data glitches; liquidation or adl entries lacking side; hand-built execution fixtures in tests missing the side field.

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/6578ea4741e9ae04. Report an issue: GitHub.