nautechsystems/nautilus_trader · critical

`handle_book_mbo` {IMPL_ERR} `{}`

Error message

`handle_book_mbo` {IMPL_ERR} `{}`

What it means

Default `Indicator::handle_book` panics when an indicator receives an MBO `OrderBook` object without overriding `handle_book`. Note the message string itself says "`handle_book_mbo` is not implemented for ..." (a known label inconsistency in the source): the method name is `handle_book` but the panic text references the MBO handler name. Either way, the default body is a guard: MBO (market-by-order) book input requires a dedicated override.

Source

Thrown at crates/indicators/src/indicator.rs:48

    fn has_inputs(&self) -> bool;

    fn initialized(&self) -> bool;

    fn handle_delta(&mut self, delta: &OrderBookDelta) {
        panic!("`handle_delta` {IMPL_ERR} `{}`", self.name());
    }

    fn handle_deltas(&mut self, deltas: &OrderBookDeltas) {
        panic!("`handle_deltas` {IMPL_ERR} `{}`", self.name());
    }

    fn handle_depth(&mut self, depth: &OrderBookDepth10) {
        panic!("`handle_depth` {IMPL_ERR} `{}`", self.name());
    }

    fn handle_book(&mut self, book: &OrderBook) {
        panic!("`handle_book_mbo` {IMPL_ERR} `{}`", self.name());
    }

    /// Updates the indicator with the given quote tick.
    ///
    /// # Errors
    ///
    /// Returns an error if the configured price type cannot be extracted from the quote.
    fn handle_quote(&mut self, quote: &QuoteTick) -> anyhow::Result<()> {
        anyhow::bail!("`handle_quote_tick` {IMPL_ERR} `{}`", self.name());
    }

    fn handle_trade(&mut self, trade: &TradeTick) {
        panic!("`handle_trade_tick` {IMPL_ERR} `{}`", self.name());
    }

    fn handle_bar(&mut self, bar: &Bar) {
        panic!("`handle_bar` {IMPL_ERR} `{}`", self.name());
    }

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Override `fn handle_book(&mut self, book: &OrderBook)` in the indicator impl to process the MBO book.
  2. Convert MBO books to a supported representation (e.g. deltas or depth) before passing to the indicator.
  3. Only register the indicator with data sources whose book type it actually implements.

Example fix

// before
// MBO OrderBook routed to indicator without handle_book

// after
impl Indicator for MyIndicator {
    fn handle_book(&mut self, book: &OrderBook) {
        // derive price/volume state from the MBO book
    }
}
Defensive patterns

Strategy: validation

Validate before calling

// ensure MBO sources are only wired to MBO-capable indicators
if book.is_mbo() && !ind.handles_mbo() { log::error!("{} cannot consume MBO book", ind.name()); return; }

Try / catch

// guard the dispatch: if mbo_capable(ind) { ind.handle_book(book); } else { convert_book_to_deltas(book, &mut ind); }

Prevention

When it happens

Trigger: Calling `handle_book(&OrderBook)` on an indicator lacking an override — typically when MBO market data (e.g. from venues that publish market-by-order) is routed to an indicator implemented for quotes, trades, or deltas only.

Common situations: Subscribing indicators to MBO data feeds (DepthMarketData like Databento MBO); venue/data-source changes switching the book representation to MBO without updating indicator implementations; generic dispatch code that calls handle_book on every indicator in a registry.

Related errors


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