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
- 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
- Check the channel subscription: use 'books'/'bbo-tbt' with full snapshot semantics and handle the initial snapshot whose one side may be empty
- Log the instrument_id and skip/continue instead of failing the whole batch in parse_quote_msg_vec
- 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
- Filter empty-side messages in the vec wrapper before individual parsing
- Keep a last-known-good quote cache to bridge one-sided updates
- Monitor instruments with persistently one-sided books and unsubscribe
- Pin and track OKX books/bbo-tbt channel semantics for snapshot vs update frames
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
- Unsupported algo order type: {:?}
- Missing sz for algo order {}
- Cannot determine spread fill quantity: fill_sz='{}' and acc_
- Cannot determine fill quantity: fill_sz is empty/zero and ac
- Cannot determine fill quantity: fill_sz='{}' and acc_fill_sz
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/0e21bd6bc9df40b6.
Report an issue: GitHub.