nautechsystems/nautilus_trader · error · anyhow::Error

invalid Binance Futures order-book depth {depth}; valid valu

Error message

invalid Binance Futures order-book depth {depth}; valid values are {BINANCE_BOOK_DEPTHS:?}

What it means

Thrown by request_book_snapshot on the Binance Futures data client when the requested order-book depth is not one of the exchange-supported levels. Binance futures /fapi/v1/depth and /dapi/v1/depth accept only the depths mirrored in BINANCE_BOOK_DEPTHS = [5, 10, 20, 50, 100, 500, 1000] (crates/adapters/binance/src/common/consts.rs:338). When request.depth is None the client defaults to 1000, which is always accepted.

Source

Thrown at crates/adapters/binance/src/futures/data.rs:3044

                        end_nanos,
                        clock.get_time_ns(),
                        params,
                    ));

                    if let Err(e) = sender.send(DataEvent::Response(response)) {
                        log::error!("Failed to send bars response: {e}");
                    }
                }
                Err(e) => log::error!("Bar request failed: {e:?}"),
            }
        });

        Ok(())
    }

    fn request_book_snapshot(&self, request: RequestBookSnapshot) -> anyhow::Result<()> {
        let depth = request.depth.map_or(1000, |value| value.get() as u32);
        anyhow::ensure!(
            BINANCE_BOOK_DEPTHS.contains(&depth),
            "invalid Binance Futures order-book depth {depth}; valid values are {BINANCE_BOOK_DEPTHS:?}"
        );
        let http = self.http_client.clone();
        let sender = self.data_sender.clone();
        let instrument_id = request.instrument_id;
        let request_id = request.request_id;
        let client_id = request.client_id.unwrap_or(self.client_id);
        let params = request.params;
        let clock = self.clock;

        get_runtime().spawn(async move {
            match http.request_book_snapshot(instrument_id, Some(depth)).await {
                Ok(book) => {
                    let response = DataResponse::Book(BookResponse::new(
                        request_id,
                        client_id,
                        instrument_id,

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Set depth to one of 5, 10, 20, 50, 100, 500, or 1000
  2. Omit depth (pass None) to use the default of 1000
  3. Validate any user-configured depth against the allowed list before submitting the snapshot request

Example fix

// before
let request = RequestBookSnapshot::new(instrument_id, client_id, request_id, Some(200.non_zero()?));

// after
let request = RequestBookSnapshot::new(instrument_id, client_id, request_id, Some(500.non_zero()?));
Defensive patterns

Strategy: validation

Validate before calling

const BINANCE_BOOK_DEPTHS: [u32; 7] = [5, 10, 20, 50, 100, 500, 1000];

let depth = requested_depth.unwrap_or(1000);
assert!(BINANCE_BOOK_DEPTHS.contains(&depth), "depth must be one of {BINANCE_BOOK_DEPTHS:?}");
// then send RequestBookSnapshot

Type guard

fn is_valid_binance_depth(depth: u32) -> bool {
    [5, 10, 20, 50, 100, 500, 1000].contains(&depth)
}

Prevention

When it happens

Trigger: Sending a RequestBookSnapshot whose depth field holds an unsupported value such as 25, 200, or 2000 — e.g. depth copied from another venue's config or computed dynamically from user settings.

Common situations: Reusing a Bybit/OKX depth setting (those venues allow 25/200) on the Binance futures adapter; passing a raw user-supplied 'limit' straight into the request without whitelisting.

Related errors


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