nautechsystems/nautilus_trader · error

Asks length mismatch: expected {DEPTH10_LEN}, was {}

Error message

Asks length mismatch: expected {DEPTH10_LEN}, was {}

What it means

The mirror case for asks: BitMEX `orderBook10` messages must supply exactly DEPTH10_LEN (25) ask levels, and the adapter enforces this when converting the ask `Vec<BookOrder>` into a fixed-size array. Failing that conversion raises this error with the actual ask count. The fixed-width depth model downstream requires exactly 25 levels per side.

Source

Thrown at crates/adapters/bitmex/src/websocket/parse.rs:335

        let ask_order = BookOrder::new(
            OrderSide::Sell,
            Price::new(level[0], price_precision),
            parse_fractional_quantity(level[1], instrument),
            0,
        );

        asks.push(ask_order);
        ask_counts[i] = 1;
    }

    let bids: [BookOrder; DEPTH10_LEN] = bids.try_into().map_err(|v: Vec<BookOrder>| {
        anyhow::anyhow!(
            "Bids length mismatch: expected {DEPTH10_LEN}, was {}",
            v.len()
        )
    })?;
    let asks: [BookOrder; DEPTH10_LEN] = asks.try_into().map_err(|v: Vec<BookOrder>| {
        anyhow::anyhow!(
            "Asks length mismatch: expected {DEPTH10_LEN}, was {}",
            v.len()
        )
    })?;

    let ts_event = UnixNanos::from(msg.timestamp);

    Ok(OrderBookDepth10::new(
        instrument_id,
        bids,
        asks,
        bid_counts,
        ask_counts,
        RecordFlag::F_SNAPSHOT as u8,
        0, // Not applicable for BitMEX L2 books
        ts_event,
        ts_init,
    ))

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Capture the raw message and check the actual ask count; handle shallow books by padding or by using an incremental L2 book path.
  2. Confirm only true `orderBook10` snapshots reach `parse_book10_msg`.
  3. Fix test fixtures to carry exactly 25 ask entries.
  4. Add a pre-validation step that rejects or normalizes depth arrays before `try_into`.

Example fix

// before
let fixture_asks = vec![ask1, ask2]; // only 2 levels
// after
assert_eq!(fixture_asks.len(), DEPTH10_LEN);
let fixture_asks = pad_levels(fixture_asks, DEPTH10_LEN);
Defensive patterns

Strategy: validation

Validate before calling

if asks.len() != DEPTH10_LEN {
    return Err(anyhow::anyhow!("asks must have exactly {DEPTH10_LEN} levels, got {}", asks.len()));
}

Type guard

fn is_full_depth(v: &[BookOrder]) -> bool { v.len() == DEPTH10_LEN }

Try / catch

match parse_book10_msg(&msg) {
    Ok(book) => book,
    Err(e) if e.to_string().contains("Asks length mismatch") => { log::debug!("skipping malformed book10: {e}"); }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: `parse_book10_msg` at crates/adapters/bitmex/src/websocket/parse.rs:335 gets an `orderBook10` message whose `asks` array length differs from 25 — short books on illiquid symbols, malformed payloads, or wrong message type routed to this parser.

Common situations: New or thinly traded symbols with shallow ask books; hand-written test fixtures with fewer than 25 asks; upstream payload changes from BitMEX; message-routing bugs sending partial depth into the book10 path.

Related errors


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