{"record":{"id":"39e0e581c5d5c71e","repo":"nautechsystems/nautilus_trader","slug":"missing-underlying-for","errorCode":null,"errorMessage":"Missing underlying for {}","messagePattern":"Missing underlying for (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/bitmex/src/websocket/messages.rs","lineNumber":585,"sourceCode":"    pub fair_basis: Option<f64>,\n    pub fair_basis_rate: Option<f64>,\n    pub fair_price: Option<f64>,\n    pub timestamp: Timestamp,\n}\n\nimpl TryFrom<BitmexInstrumentMsg> for crate::http::models::BitmexInstrument {\n    type Error = anyhow::Error;\n\n    fn try_from(msg: BitmexInstrumentMsg) -> Result<Self, Self::Error> {\n        use crate::common::enums::{BitmexInstrumentState, BitmexInstrumentType};\n\n        // Required fields\n        let root_symbol = msg\n            .root_symbol\n            .ok_or_else(|| anyhow::anyhow!(\"Missing root_symbol for {}\", msg.symbol))?;\n        let underlying = msg\n            .underlying\n            .ok_or_else(|| anyhow::anyhow!(\"Missing underlying for {}\", msg.symbol))?;\n        let quote_currency = msg\n            .quote_currency\n            .ok_or_else(|| anyhow::anyhow!(\"Missing quote_currency for {}\", msg.symbol))?;\n        let tick_size = msg\n            .tick_size\n            .ok_or_else(|| anyhow::anyhow!(\"Missing tick_size for {}\", msg.symbol))?;\n        let multiplier = msg\n            .multiplier\n            .ok_or_else(|| anyhow::anyhow!(\"Missing multiplier for {}\", msg.symbol))?;\n        let is_quanto = msg\n            .is_quanto\n            .ok_or_else(|| anyhow::anyhow!(\"Missing is_quanto for {}\", msg.symbol))?;\n        let is_inverse = msg\n            .is_inverse\n            .ok_or_else(|| anyhow::anyhow!(\"Missing is_inverse for {}\", msg.symbol))?;\n\n        // Parse state - default to Open if not present\n        let state = msg","sourceCodeStart":567,"sourceCodeEnd":603,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/bitmex/src/websocket/messages.rs#L567-L603","documentation":"Same required-field guard family in the instrument message TryFrom: `underlying` is null in the received BitmexInstrumentMsg, so the full instrument definition cannot be constructed and the conversion fails.","triggerScenarios":"A WS `instrument` message for a symbol (typically derivatives) arriving with underlying: null — partial snapshots, spot/index symbols, or delisted contracts.","commonSituations":"Bulk instrument subscriptions including non-derivative symbols; BitMEX emitting deltas where absent fields are null rather than omitted; older API messages missing recently added/required fields.","solutions":["Catch and skip the record; process instruments that do carry underlying.","Cache full snapshots and apply partial updates only to cached definitions.","Filter subscriptions to standard derivative symbols with complete definitions.","Update adapter field mappings if BitMEX changed the message schema."],"exampleFix":"// before\nlet instrument = TryInto::<Instrument>::try_into(msg)?;\n// after\nif let Err(e) = TryInto::<Instrument>::try_into(msg) {\n    log::debug!(\"Ignoring incomplete instrument update: {e}\");\n    return Ok(());\n}","handlingStrategy":"fallback","validationCode":"if msg.underlying.is_none() { /* defer to next full snapshot */ }","typeGuard":"fn has_definition(msg: &BitmexInstrumentMsg) -> bool {\n    msg.root_symbol.is_some() && msg.underlying.is_some() && msg.quote_currency.is_some() && msg.tick_size.is_some()\n}","tryCatchPattern":"let def = match TryInto::<InstrumentDef>::try_into(msg) {\n    Ok(d) => d,\n    Err(e) => { debug!(\"skipping: {e}\"); return Ok(()); }\n};","preventionTips":["Cache full instrument definitions and apply WS deltas to the cache.","Filter subscriptions to derivative symbols that carry underlying.","Handle partial WS snapshots as deltas, not standalone definitions."],"tags":["websocket","bitmex","instrument","missing-field"],"backgroundTag":"missing-required-config-field","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"}