{"record":{"id":"6578ea4741e9ae04","repo":"nautechsystems/nautilus_trader","slug":"skipping-execution-without-side","errorCode":null,"errorMessage":"Skipping execution without side: {:?}","messagePattern":"Skipping execution without side: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"crates/adapters/bitmex/src/http/parse.rs","lineNumber":1109,"sourceCode":"\n    // Additional check: skip executions without order_id (likely funding/settlement)\n    let order_id = exec.order_id.ok_or_else(|| {\n        anyhow::anyhow!(\"Skipping execution without order_id: {:?}\", exec.exec_type)\n    })?;\n\n    let account_id = bitmex_account_id(exec.account);\n    let instrument_id = instrument.id();\n    let venue_order_id = VenueOrderId::new(order_id.to_string());\n    // trd_match_id might be missing for some execution types, use exec_id as fallback\n    let trade_id = TradeId::new(\n        exec.trd_match_id\n            .or(Some(exec.exec_id))\n            .ok_or_else(|| anyhow::anyhow!(\"Fill missing both trd_match_id and exec_id\"))?\n            .to_string(),\n    );\n    // Skip executions without side (likely not trades)\n    let Some(side) = exec.side else {\n        anyhow::bail!(\"Skipping execution without side: {:?}\", exec.exec_type);\n    };\n    let order_side = OrderSide::from(side);\n    let last_qty = parse_signed_contracts_quantity(exec.last_qty, instrument);\n    let last_px = Price::new(exec.last_px, instrument.price_precision());\n\n    // Map BitMEX currency to standard currency code\n    let settlement_currency_str = exec.settl_currency.unwrap_or(Ustr::from(\"XBT\")).as_str();\n    let mapped_currency = map_bitmex_currency(settlement_currency_str);\n    let currency = get_currency(&mapped_currency);\n    let commission = Money::new(exec.commission.unwrap_or(0.0), currency);\n    let liquidity_side = parse_liquidity_side(&exec.last_liquidity_ind);\n    let client_order_id = exec.cl_ord_id.map(ClientOrderId::new);\n    let venue_position_id = None; // Not applicable on BitMEX\n    let ts_event = exec.transact_time.map_or(ts_init, UnixNanos::from);\n\n    Ok(FillReport::new(\n        account_id,\n        instrument_id,","sourceCodeStart":1091,"sourceCodeEnd":1127,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/bitmex/src/http/parse.rs#L1091-L1127","documentation":"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.","triggerScenarios":"request_fill_reports encountering a Trade-typed execution record whose side field is null, or a directly constructed/test execution without side set.","commonSituations":"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.","solutions":["Skip executions where exec.side is None before calling parse_fill_report","Log the exec_id of side-less executions and verify against BitMEX's dashboard whether they represent real fills","Re-fetch the execution via /execution/tradeHistory, which usually populates side for genuine trades","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"],"exampleFix":"// before\nlet fill = parse_fill_report(&exec, &instrument, ts_init)?;\n// after\nlet Some(side) = exec.side else {\n    tracing::warn!(\"skipping execution {} without side\", exec.exec_id);\n    continue;\n};\nlet fill = parse_fill_report(&exec, &instrument, ts_init)?;","handlingStrategy":"validation","validationCode":"fn parseable_fill(exec: &BitmexExecution) -> bool {\n    matches!(exec.exec_type, BitmexExecType::Trade) && exec.side.is_some()\n}\n// only call parse_fill_report when parseable_fill(&exec)","typeGuard":"fn side_of(exec: &BitmexExecution) -> Option<BitmexSide> {\n    exec.side\n}","tryCatchPattern":"match parse_fill_report(exec, instrument, ts_init) {\n    Ok(fill) => fills.push(fill),\n    Err(e) if e.to_string().contains(\"without side\") => {\n        warn!(\"exec {} had no side; skipped\", exec.exec_id);\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Validate side is present along with exec_type before parsing","Log exec_id of side-less rows and reconcile against the BitMEX dashboard","Prefer /execution/tradeHistory which populates side for real trades","Sanity-check test fixtures include side when mimicking trade executions"],"tags":["rust","bitmex","fills","parsing"],"backgroundTag":"missing-required-argument","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}