nautechsystems/nautilus_trader · error

invalid depth {depth}; valid values are {BYBIT_BOOK_DEPTHS:?

Error message

invalid depth {depth}; valid values are {BYBIT_BOOK_DEPTHS:?}

What it means

Bybit's order book websocket only supports a fixed set of depth values (BYBIT_BOOK_DEPTHS, e.g. 1, 50, 200, 500). validate_orderbook_depth rejects any requested depth outside that set before subscribing, because the exchange would reject or misinterpret the subscription.

Source

Thrown at crates/adapters/bybit/src/data.rs:435

        if self.shutdown_errors.is_empty() {
            Ok(())
        } else {
            let errors = std::mem::take(&mut self.shutdown_errors);
            anyhow::bail!("Bybit data shutdown failed: {}", errors.join("; "))
        }
    }
}

fn send_data(sender: &tokio::sync::mpsc::UnboundedSender<DataEvent>, data: Data) {
    if let Err(e) = sender.send(DataEvent::Data(data)) {
        log::error!("Failed to emit data event: {e}");
    }
}

fn validate_orderbook_depth(depth: u32) -> anyhow::Result<()> {
    if !BYBIT_BOOK_DEPTHS.contains(&depth) {
        anyhow::bail!("invalid depth {depth}; valid values are {BYBIT_BOOK_DEPTHS:?}");
    }

    Ok(())
}

/// Cached funding state per symbol: (funding_rate, next_funding_time, funding_interval_hour).
type FundingCacheEntry = (Option<String>, Option<String>, Option<String>);

#[expect(clippy::too_many_arguments)]
fn handle_ws_message(
    message: &BybitWsMessage,
    data_sender: &tokio::sync::mpsc::UnboundedSender<DataEvent>,
    instruments: &AHashMap<Ustr, InstrumentAny>,
    product_type: Option<BybitProductType>,
    trade_subs: &Arc<AtomicSet<InstrumentId>>,
    ticker_subs: &Arc<AtomicMap<InstrumentId, AHashSet<&'static str>>>,
    quote_depths: &Arc<AtomicMap<InstrumentId, u32>>,
    book_depths: &Arc<AtomicMap<InstrumentId, u32>>,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Set the subscription depth to a value listed in BYBIT_BOOK_DEPTHS for the product type
  2. Check BYBIT_BOOK_DEPTHS in the bybit adapter crate for allowed values per product
  3. Use the default depth (BYBIT_DEFAULT_ORDERBOOK_DEPTH) by leaving depth unset
  4. Clamp/round your requested depth down to the nearest supported value before subscribing

Example fix

// before
client.subscribe_book_deltas(cmd_with_depth(500))? // rejected for this product
// after
client.subscribe_book_deltas(cmd_with_depth(200))? // a BYBIT_BOOK_DEPTHS value
Defensive patterns

Strategy: validation

Validate before calling

fn depth_ok(depth: u32) -> bool { BYBIT_BOOK_DEPTHS.contains(&depth) }
// clamp before subscribe:
let depth = *BYBIT_BOOK_DEPTHS.iter().filter(|&&d| d <= requested).max().unwrap_or(&BYBIT_DEFAULT_ORDERBOOK_DEPTH);

Try / catch

if let Err(e) = client.subscribe_book_deltas(cmd) {
    log::warn!("depth rejected, retrying with default: {e}");
    client.subscribe_book_deltas(cmd_with_depth(BYBIT_DEFAULT_ORDERBOOK_DEPTH))?;
}

Prevention

When it happens

Trigger: subscribe_book_deltas with a SubscribeBookDeltas command whose depth (or default) is not one of BYBIT_BOOK_DEPTHS — e.g. requesting depth=100 or depth=500 when the product line caps lower (test case rejects 500).

Common situations: Configuring a generic depth value in a strategy config that works on Binance but not Bybit; requesting max depth beyond what the Bybit product supports; copying depth settings between adapters.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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