nautechsystems/nautilus_trader · error
Missing quote_currency for {}
Error message
Missing quote_currency for {} What it means
The instrument message conversion requires `quote_currency`, which arrived null in the BitmexInstrumentMsg. Without a quote currency no instrument can be defined, so the conversion aborts with this error naming the symbol.
Source
Thrown at crates/adapters/bitmex/src/websocket/messages.rs:588
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))?;
// Parse state - default to Open if not present
let state = msg
.state
.and_then(|s| serde_json::from_str::<BitmexInstrumentState>(&format!("\"{s}\"")).ok())
.unwrap_or(BitmexInstrumentState::Open);View on GitHub (pinned to 18893faf8b)
Solutions
- Skip the affected symbol; convert only messages with all required fields present.
- Maintain a snapshot cache so partial deltas never drive a full conversion.
- Exclude index/special symbols from instrument subscriptions.
- Verify BitMEX instrument schema and update adapter mappings if changed.
Example fix
// before
let def = BitmexInstrumentDef::try_from(msg).context("convert instrument")?;
// after
let Ok(def) = BitmexInstrumentDef::try_from(msg) else {
log::debug!("Skipping instrument msg missing required fields");
return Ok(());
}; Defensive patterns
Strategy: fallback
Validate before calling
if msg.quote_currency.is_none() { /* skip symbol */ } Type guard
fn convertible(msg: &BitmexInstrumentMsg) -> bool {
msg.root_symbol.is_some() && msg.underlying.is_some() && msg.quote_currency.is_some()
} Try / catch
if let Err(e) = convert_instrument(&msg) {
debug!("instrument {} skipped: {e}", msg.symbol);
} Prevention
- Exclude index/special symbols (e.g. .BVOL) from instrument subscriptions.
- Refetch a complete definition via REST when a WS row is incomplete.
- Treat each WS instrument row independently so one failure does not abort the batch.
When it happens
Trigger: WS instrument message for a symbol with quote_currency: null — index symbols (e.g. .BVOL), partial snapshots, or malformed/delisted instrument rows.
Common situations: Subscribing to all instruments (indices and special symbols included); BitMEX schema changes; cached definitions not merged with partial delta updates.
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 root_symbol for {}
- Missing underlying 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/7d9cf8f2cd03b48f.
Report an issue: GitHub.