nautechsystems/nautilus_trader · error · anyhow::Error
missing size component in {label} level
Error message
missing size component in {label} level What it means
parse_book_level expects a 2-element array [price, size] per orderbook level. This error means the price element existed but the size element (index 1) was missing, so the level cannot be converted into a Quantity. Thrown by the Bybit adapter while building orderbook deltas.
Source
Thrown at crates/adapters/bybit/src/common/parse.rs:964
push_level(level, OrderSide::Sell)?;
}
OrderBookDeltas::new_checked(instrument_id, deltas)
.context("failed to assemble OrderBookDeltas from Bybit message")
}
pub fn parse_book_level(
level: &[String],
price_precision: u8,
size_precision: u8,
label: &str,
) -> anyhow::Result<(Price, Quantity)> {
let price_str = level
.first()
.ok_or_else(|| anyhow::anyhow!("missing price component in {label} level"))?;
let size_str = level
.get(1)
.ok_or_else(|| anyhow::anyhow!("missing size component in {label} level"))?;
let price = parse_price_with_precision(price_str, price_precision, label)?;
let size = parse_quantity_with_precision(size_str, size_precision, label)?;
Ok((price, size))
}
/// Parses a kline entry into a [`Bar`].
pub fn parse_kline_bar(
kline: &BybitKline,
instrument: &InstrumentAny,
bar_type: BarType,
timestamp_on_close: bool,
ts_init: Option<UnixNanos>,
) -> anyhow::Result<Bar> {
let price_precision = instrument.price_precision();
let size_precision = instrument.size_precision();
let open = parse_price_with_precision(&kline.open, price_precision, "kline.open")?;
let high = parse_price_with_precision(&kline.high, price_precision, "kline.high")?;View on GitHub (pinned to 18893faf8b)
Solutions
- Inspect the raw frame and ensure each level contains both price and size elements.
- Validate level.len() == 2 in the caller before parsing; skip/log malformed entries.
- Update the adapter or Bybit API version alignment if the message schema changed.
Example fix
// before
let (p, s) = parse_book_level(level, price_precision, size_precision, "bid")?;
// after
if level.len() != 2 { anyhow::bail!("expected [price,size], got {level:?}"); }
let (p, s) = parse_book_level(level, price_precision, size_precision, "bid")?; Defensive patterns
Strategy: validation
Validate before calling
// Rust: skip levels lacking a size component
if level.len() != 2 { log::warn!("malformed level: {level:?}"); continue; } Type guard
fn has_price_and_size(level: &[serde_json::Value]) -> bool {
level.len() == 2 && level.iter().all(|v| v.is_string())
} Try / catch
let (price, size) = parse_book_level(level, pp, sp, label)
.inspect_err(|e| log::warn!("dropping {label} level: {e:#}"))?; Prevention
- Assert snapshot and delta levels always carry both price and size
- Keep deserialization schemas in sync with Bybit API changelog
- Test the orderbook parser against recorded real exchange frames
When it happens
Trigger: parse_orderbook passes a level array with exactly one element (level.get(1) returns None) to parse_book_level.
Common situations: Partial/truncated WebSocket updates; a custom transformer emitting only prices; schema drift from a Bybit API version change where size fields moved or were dropped.
Related errors
- missing price component in {label} level
- Invalid topic format: empty topic
- Bybit order book update missing bid levels and no previous q
- Bybit order book update missing ask levels and no previous q
- unrecognized side '{side}'
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/30efc175d8b3bce5.
Report an issue: GitHub.