nautechsystems/nautilus_trader · error

invalid negative order-book update ID

Error message

invalid negative order-book update ID

What it means

Thrown by request_book_snapshot when snapshot.last_update_id is negative and therefore cannot convert to u64. The depth response's last_update_id is the book sequence number and must be a non-negative integer by protocol; a negative value means the response was malformed or deserialization mangled the field, and NautilusTrader refuses to construct an OrderBook with a bogus sequence rather than corrupting subsequent delta matching.

Source

Thrown at crates/adapters/binance/src/futures/http/client.rs:3073

        instrument_id: InstrumentId,
        depth: Option<u32>,
    ) -> anyhow::Result<OrderBook> {
        if depth.is_some_and(|value| !crate::common::consts::BINANCE_BOOK_DEPTHS.contains(&value)) {
            anyhow::bail!(
                "invalid Binance Futures order-book depth; valid values are {:?}",
                crate::common::consts::BINANCE_BOOK_DEPTHS
            );
        }
        let (symbol, price_precision, size_precision) =
            self.cached_precisions_by_id(instrument_id)?;
        let params = BinanceDepthParams {
            symbol,
            limit: depth,
        };
        let snapshot = self.inner.depth(&params).await?;
        let ts_event = self.clock.get_time_ns();
        let sequence = u64::try_from(snapshot.last_update_id)
            .map_err(|_| anyhow::anyhow!("invalid negative order-book update ID"))?;
        let mut book = OrderBook::new(instrument_id, BookType::L2_MBP);
        for (index, level) in snapshot.bids.iter().enumerate() {
            let order = BookOrder::new(
                OrderSide::Buy,
                parse_required_price_at_precision(&level.0, price_precision, "bid price")?,
                parse_required_quantity_at_precision(&level.1, size_precision, "bid quantity")?,
                index as u64,
            );
            book.add(order, 0, sequence, ts_event);
        }
        let bid_count = snapshot.bids.len();
        for (index, level) in snapshot.asks.iter().enumerate() {
            let order = BookOrder::new(
                OrderSide::Sell,
                parse_required_price_at_precision(&level.0, price_precision, "ask price")?,
                parse_required_quantity_at_precision(&level.1, size_precision, "ask quantity")?,
                (bid_count + index) as u64,
            );

View on GitHub (pinned to a4b06ed870)

Solutions

  1. If seen in tests: fix the fixture so last_update_id is a realistic non-negative u64
  2. If seen live: log the raw response body and check for a proxy or gateway mutating payloads; verify the adapter version matches the current Binance API schema
  3. Treat occurrence as a data-integrity alarm — halt book processing for the instrument rather than resynchronizing on the bad sequence

Example fix

// before (test fixture)
let snapshot = BinanceDepthResponse { last_update_id: -1, bids: vec![], asks: vec![] };

// after
let snapshot = BinanceDepthResponse { last_update_id: 42, bids: vec![], asks: vec![] };
Defensive patterns

Strategy: try-catch

Validate before calling

if snapshot.last_update_id < 0 {
    log::error!("malformed depth payload: negative last_update_id={}", snapshot.last_update_id);
    // reject payload before building the book
}

Try / catch

Treat as a data-integrity failure: drop the snapshot, log the raw payload, and re-request the depth snapshot; do not resynchronize an existing book onto a bogus sequence.

Prevention

When it happens

Trigger: A Binance depth response (or a mocked/replayed one in tests) where last_update_id is negative; proxy/fixture tooling that substitutes dummy negative values; a serde type change causing an offset field to land in last_update_id; effectively unreachable against the real venue and therefore almost always a test-harness or deserialization defect when seen.

Common situations: Unit tests with hand-written depth fixtures using placeholder IDs like -1; replay harnesses with synthesized snapshots; schema drift between the Binance response model and the venue's actual JSON after an API revision.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16). Data as JSON: /api/errors/547e0c21297ce3bb. Report an issue: GitHub.