nautechsystems/nautilus_trader · critical

Error: No bid orders for best bid price

Error message

Error: No bid orders for best bid price

What it means

This Rust panic occurs in the FFI wrapper `orderbook_best_bid_price` when `OrderBook::best_bid_price()` returns None, i.e. the book's bid side contains no orders so there is no best bid price to return. Because the wrapper runs inside `abort_on_panic`, the panic aborts the whole process rather than returning an error to the FFI caller (e.g. Python).

Source

Thrown at crates/model/src/ffi/orderbook/book.rs:261

#[unsafe(no_mangle)]
pub extern "C" fn orderbook_has_bid(book: &mut OrderBook) -> u8 {
    u8::from(book.has_bid())
}

#[unsafe(no_mangle)]
pub extern "C" fn orderbook_has_ask(book: &mut OrderBook) -> u8 {
    u8::from(book.has_ask())
}

/// # Panics
///
/// Panics if there are no bid orders for best bid price.
#[unsafe(no_mangle)]
#[cfg_attr(feature = "high-precision", allow(improper_ctypes_definitions))]
pub extern "C" fn orderbook_best_bid_price(book: &mut OrderBook) -> Price {
    abort_on_panic(|| {
        book.best_bid_price()
            .expect("Error: No bid orders for best bid price")
    })
}

/// # Panics
///
/// Panics if there are no ask orders for best ask price.
#[unsafe(no_mangle)]
#[cfg_attr(feature = "high-precision", allow(improper_ctypes_definitions))]
pub extern "C" fn orderbook_best_ask_price(book: &mut OrderBook) -> Price {
    abort_on_panic(|| {
        book.best_ask_price()
            .expect("Error: No ask orders for best ask price")
    })
}

/// # Panics
///
/// Panics if there are no bid orders for best bid size.

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Check the book has bids before calling: `book.has_orders()` and `book.best_bid_price()` / `book.get_price(Side.BUY)` availability (or check `book.bids()` is non-empty) in the caller.
  2. Ensure the book is initialized with an initial snapshot (e.g. `OrderBookDeltas` or quote/trade data) before querying best prices.
  3. Handle empty-book cases at the strategy level by treating best bid as None and skipping the calculation.
  4. Verify you are querying the correct instrument_id's book and that the data feed is connected and publishing bid-side data.

Example fix

// before (Python FFI caller)
best_bid = orderbook_best_bid_price(book)
// after
if book_update_count > 0 and has_bid_orders(book):
    best_bid = orderbook_best_bid_price(book)
else:
    best_bid = None
Defensive patterns

Strategy: validation

Validate before calling

def can_get_best_bid(book) -> bool:
    return book.has_orders() and book.bids_len() > 0  # or check best bid price availability

Type guard

def has_bid_side(book) -> bool:
    try:
        return len(book.bids()) > 0
    except Exception:
        return False

Prevention

When it happens

Trigger: Calling the FFI function `orderbook_best_bid_price(book)` on an OrderBook whose bid side is empty: no quotes/trades/depth updates have populated bids, all bids were deleted, or the book was just created/cleared.

Common situations: Querying a book before the first market-data snapshot arrives; a depth feed that only sent ask-side updates; book_l1/book_l3 data cleared by a `clear` call; instrument-specific books for symbols with no bids (illiquid markets).

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


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