nautechsystems/nautilus_trader · error
Missing root_symbol for {}
Error message
Missing root_symbol for {} What it means
The TryFrom<BitmexInstrumentMsg> conversion for instrument definitions requires `root_symbol`, but the WebSocket instrument message omitted it (null). The conversion fails so an incomplete instrument definition is never used downstream.
Source
Thrown at crates/adapters/bitmex/src/websocket/messages.rs:582
pub indicative_tax_rate: Option<f64>,
pub open_interest: Option<i64>,
pub open_value: Option<i64>,
pub fair_basis: Option<f64>,
pub fair_basis_rate: Option<f64>,
pub fair_price: Option<f64>,
pub timestamp: Timestamp,
}
impl TryFrom<BitmexInstrumentMsg> for crate::http::models::BitmexInstrument {
type Error = anyhow::Error;
fn try_from(msg: BitmexInstrumentMsg) -> Result<Self, Self::Error> {
use crate::common::enums::{BitmexInstrumentState, BitmexInstrumentType};
// Required fields
let root_symbol = msg
.root_symbol
.ok_or_else(|| anyhow::anyhow!("Missing root_symbol for {}", msg.symbol))?;
let underlying = msg
.underlying
.ok_or_else(|| anyhow::anyhow!("Missing underlying for {}", msg.symbol))?;
let quote_currency = msg
.quote_currency
.ok_or_else(|| anyhow::anyhow!("Missing quote_currency for {}", msg.symbol))?;
let tick_size = msg
.tick_size
.ok_or_else(|| anyhow::anyhow!("Missing tick_size for {}", msg.symbol))?;
let multiplier = msg
.multiplier
.ok_or_else(|| anyhow::anyhow!("Missing multiplier for {}", msg.symbol))?;
let is_quanto = msg
.is_quanto
.ok_or_else(|| anyhow::anyhow!("Missing is_quanto for {}", msg.symbol))?;
let is_inverse = msg
.is_inverse
.ok_or_else(|| anyhow::anyhow!("Missing is_inverse for {}", msg.symbol))?;View on GitHub (pinned to 18893faf8b)
Solutions
- Skip/catch the failed conversion for that symbol and continue processing other instruments.
- Restrict the instrument subscription to symbols with complete definitions.
- Merge partial WS updates into a cached full instrument snapshot instead of converting each update standalone.
- Check whether the symbol is an index/composite that legitimately lacks root_symbol and handle it separately.
Example fix
// before
let instrument = BitmexInstrumentMsg::try_from(msg)?;
// after
match BitmexInstrumentMsg::try_from(msg) {
Ok(i) => handle(i),
Err(e) => log::debug!("Skipping incomplete instrument msg: {e}"),
} Defensive patterns
Strategy: fallback
Validate before calling
if msg.root_symbol.is_none() { /* skip or fetch full snapshot via REST */ } Type guard
fn complete_instrument(msg: &BitmexInstrumentMsg) -> bool {
msg.root_symbol.is_some() && msg.underlying.is_some() && msg.quote_currency.is_some()
} Try / catch
match TryInto::<InstrumentDef>::try_into(msg) {
Ok(def) => apply(def),
Err(e) => log::debug!("partial instrument update ignored: {e}"),
} Prevention
- Bootstrap instruments from a full REST snapshot before consuming WS deltas.
- Expect index/composite symbols to lack derivative-only fields.
- Skip (do not fail) individual instrument conversions inside bulk subscriptions.
When it happens
Trigger: Receiving an `instrument` WS message for a symbol whose root_symbol is null — e.g. composite/index symbols, delisted instruments, or BitMEX emitting partial instrument snapshots.
Common situations: Subscribing to the full instrument table where some rows (indices, .XBT symbols) lack root_symbol; BitMEX partial updates carrying only changed fields.
Understand the failure class
Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.
Related errors
- Missing underlying for {}
- Missing quote_currency for {}
- Missing tick_size for {}
- Missing multiplier for {}
- Missing is_quanto for {}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/ff283e42929d3f2e.
Report an issue: GitHub.