nautechsystems/nautilus_trader · warning · anyhow::Error

Empty asks array for {instrument_id}

Error message

Empty asks array for {instrument_id}

What it means

OKX quote (BBO ticker) messages must contain at least one bid and one ask to build a QuoteTick. This error is thrown in parse_quote_msg when msg.asks.first() is None, i.e. the exchange delivered a tick with no ask entries. The parser treats a one-sided or empty book snapshot as unparseable rather than emitting a partial quote.

Source

Thrown at crates/adapters/okx/src/websocket/parse.rs:1043

///
/// # Errors
///
/// Returns an error if any quote levels contain values that cannot be parsed.
pub fn parse_quote_msg(
    msg: &OKXBookMsg,
    instrument_id: InstrumentId,
    price_precision: u8,
    size_precision: u8,
    ts_init: UnixNanos,
) -> anyhow::Result<QuoteTick> {
    let best_bid: &OrderBookEntry = msg
        .bids
        .first()
        .ok_or_else(|| anyhow::anyhow!("Empty bids array for {instrument_id}"))?;
    let best_ask: &OrderBookEntry = msg
        .asks
        .first()
        .ok_or_else(|| anyhow::anyhow!("Empty asks array for {instrument_id}"))?;

    let bid_price = parse_price(&best_bid.price, price_precision)?;
    let ask_price = parse_price(&best_ask.price, price_precision)?;
    let bid_size = parse_quantity(&best_bid.size, size_precision)?;
    let ask_size = parse_quantity(&best_ask.size, size_precision)?;
    let ts_event = parse_millisecond_timestamp(msg.ts);

    QuoteTick::new_checked(
        instrument_id,
        bid_price,
        ask_price,
        bid_size,
        ask_size,
        ts_event,
        ts_init,
    )
}

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Skip quotes with empty asks before parsing: filter out msgs where msg.asks.is_empty() in the vec wrapper, keeping the last known quote as fallback
  2. Check the channel subscription: use 'books'/'bbo-tbt' with full snapshot semantics and handle the initial snapshot whose one side may be empty
  3. Log the instrument_id and skip/continue instead of failing the whole batch in parse_quote_msg_vec
  4. Verify instrument is actively traded; unsubscribe from instruments whose book is persistently one-sided

Example fix

// before
let best_ask: &OrderBookEntry = msg
    .asks
    .first()
    .ok_or_else(|| anyhow::anyhow!("Empty asks array for {instrument_id}"))?;
// after
let Some(best_ask) = msg.asks.first() else {
    log::debug("Skipping quote for {instrument_id}: empty asks array");
    return Ok(None); // or continue to next message
};
Defensive patterns

Strategy: validation

Validate before calling

// Rust, before calling the quote parse path
if msg.bids.is_empty() || msg.asks.is_empty() {
    log::debug("Skipping quote for {}: one-sided/empty book", msg.inst_id);
    return Ok(None);
}

Type guard

fn has_two_sided_book(bids: &[OrderBookEntry], asks: &[OrderBookEntry]) -> bool {
    !bids.is_empty() && !asks.is_empty()
}

Try / catch

match parse_quote_msg(&msg, instrument_id, price_precision, size_precision, ts_init) {
    Ok(quote) => emit(quote),
    Err(e) if e.to_string().contains("Empty asks array") || e.to_string().contains("Empty bids array") => {
        log::debug("Skipping one-sided quote: {e}");
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: A WebSocket 'bbo-tbt' / quote tickers message arrives whose 'asks' array is empty (e.g. the matching engine temporarily has no resting asks, or an unusually shaped update frame arrives for an illiquid instrument). Raised in parse_quote_msg, called from parse_quote_msg_vec.

Common situations: Illiquid or newly listed instruments with one-sided books; deep-in-the-money far-dated contracts; OKX sending a partial book state during volatile sessions; subscribing to books channel with a depth where one side is momentarily empty.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/0e21bd6bc9df40b6. Report an issue: GitHub.