nautechsystems/nautilus_trader · error

Fill missing both trd_match_id and exec_id

Error message

Fill missing both trd_match_id and exec_id

What it means

parse_fill_report builds a TradeId from `trd_match_id`, falling back to `exec_id`. This error fires only when BOTH fields are absent, meaning the fill cannot be uniquely identified. The parser fails so the record is not silently mis-attributed.

Source

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

    // Skip non-trade executions (funding, settlements, etc.)
    // Trade executions have exec_type of Trade and must have order_id
    if !matches!(exec.exec_type, BitmexExecType::Trade) {
        anyhow::bail!("Skipping non-trade execution: {:?}", exec.exec_type);
    }

    // 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

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Catch and skip the record in the caller, logging the raw execution for diagnosis.
  2. Verify the BitMEX API response shape for the affected executions (dump raw JSON).
  3. Update the adapter if BitMEX changed field naming/optionality.
  4. Filter executions to those with an exec_id before parsing.

Example fix

// before
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());
// after
let Some(id_src) = exec.trd_match_id.or(Some(exec.exec_id)) else {
    log::warn!("Skipping fill without trd_match_id/exec_id");
    return Ok(None);
};
let trade_id = TradeId::new(id_src.to_string());
Defensive patterns

Strategy: type-guard

Validate before calling

if exec.trd_match_id.is_none() && exec.exec_id.is_empty() { /* skip record */ }

Type guard

fn has_trade_id(exec: &BitmexExecution) -> bool {
    exec.trd_match_id.is_some() || !exec.exec_id.is_empty()
}

Try / catch

let Ok(report) = parse_fill_report(exec, instrument) else {
    log::debug!("fill without trade id skipped");
    continue;
};

Prevention

When it happens

Trigger: request_fill_reports encountering an execution row where both trd_match_id and exec_id are null — malformed or highly unusual BitMEX execution payloads.

Common situations: Unusual execution types in fill history (transfers, adjustments); BitMEX API schema drift where a previously-guaranteed field becomes optional; corrupted/partial REST responses.

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/1958953e6aab7403. Report an issue: GitHub.