nautechsystems/nautilus_trader · error · anyhow::Error
Binance Spot supports L1_MBP and L2_MBP order book…
Error message
Binance Spot supports L1_MBP and L2_MBP order book subscriptions
What it means
`subscribe_book_deltas` for Binance Spot only supports depth-1 (L1_MBP, top-of-book) and full L2 depth (L2_MBP) order book subscriptions. Any other book type (e.g. L3_MBP or depth variants Spot does not offer) is rejected with this error before any subscription is made.
Solutions
- Set the subscription book_type to `BookType::L2_MBP` (or L1_MBP) for Binance Spot instruments
- Remove any existing L1_MBP subscription for the instrument before requesting L2_MBP, as they are mutually exclusive
- Run the strategy against Binance USDT-M Futures instead if a deeper/other book type is required
- Add an instrument/exchange guard in strategy config so non-Spot book types are only requested on supported venues
Example fix
// before subscribe_book_deltas(instrument_id, BookType::L3_MBP); // after subscribe_book_deltas(instrument_id, BookType::L2_MBP); // Spot supports L1_MBP/L2_MBP only
Defensive patterns
Strategy: validation
Validate before calling
fn validate_spot_book_sub(book_type: BookType, instrument_id: InstrumentId,
l1_subs: &HashSet<InstrumentId>) -> Result<(), String> {
match book_type {
BookType::L1_MBP | BookType::L2_MBP => {},
other => return Err(format!("{other:?} not supported on Binance Spot")),
}
if book_type == BookType::L2_MBP && l1_subs.contains(&instrument_id) {
return Err(format!("L1 already subscribed for {instrument_id}; unsubscribe first"));
}
Ok(())
} Type guard
fn is_spot_supported_book_type(bt: BookType) -> bool {
matches!(bt, BookType::L1_MBP | BookType::L2_MBP)
} Try / catch
match data_engine.subscribe_book_deltas(cmd).await {
Err(e) if e.to_string().contains("L1_MBP and L2_MBP") => {
log::warn!("falling back to L2_MBP for {instrument_id}");
data_engine.subscribe_book_deltas(cmd.with_book_type(BookType::L2_MBP)).await?;
}
other => other?,
} Prevention
- Restrict order book subscriptions to L1_MBP/L2_MBP when targeting Binance Spot
- Do not mix L1 and L2 subscriptions for the same instrument
- Keep venue-specific subscription configs separate per exchange (Spot vs Futures)
- Centralize subscription building so book_type can be validated in one place
When it happens
Trigger: Calling `subscribe_book_deltas` with a subscription command whose `book_type` is neither `BookType::L1_MBP` nor `BookType::L2_MBP`; also rejected if an L1 subscription already exists for the instrument and an L2 subscribe is requested (mutually exclusive per instrument).
Common situations: Porting a strategy configured for futures (which supports other depth modes) to Spot; a generic data-engine config requesting L3/diff depth on a Spot instrument; mixing L1 and L2 subscriptions for the same instrument in one strategy.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- Binance Futures supports L1_MBP and L2_MBP order book…
- Binance liquidation custom data requires BINANCE venue…
- Binance Spot L1_MBP supports depth 1 only
- cannot subscribe L1_MBP and L2_MBP for the same Binance…
- Coinbase only supports L2_MBP order book deltas
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/f98c5b6cb57bc4e1.
Report an issue: GitHub.
Appendix: source
Thrown at crates/adapters/binance/src/spot/data.rs:1848
fn subscribe_book_deltas(&mut self, cmd: SubscribeBookDeltas) -> anyhow::Result<()> {
if cmd.book_type == BookType::L1_MBP {
anyhow::ensure!(
cmd.depth.is_none_or(|depth| depth.get() == 1),
"Binance Spot L1_MBP supports depth 1 only"
);
anyhow::ensure!(
!self.book_subscriptions.contains_key(&cmd.instrument_id),
"cannot subscribe L1_MBP and L2_MBP for the same Binance Spot instrument"
);
self.l1_book_subscriptions.rcu(|subscriptions| {
*subscriptions.entry(cmd.instrument_id).or_insert(0) += 1;
});
self.subscribe_top_of_book(cmd.instrument_id);
return Ok(());
}
if cmd.book_type != BookType::L2_MBP {
anyhow::bail!("Binance Spot supports L1_MBP and L2_MBP order book subscriptions");
}
anyhow::ensure!(
!self.l1_book_subscriptions.contains_key(&cmd.instrument_id),
"cannot subscribe L1_MBP and L2_MBP for the same Binance Spot instrument"
);
let instrument_id = cmd.instrument_id;
let ws = self.ws_client.clone();
let symbol_lower = instrument_id.symbol.as_str().to_lowercase();
if self.spot_market_data_mode == BinanceSpotMarketDataMode::Json && cmd.depth.is_some() {
// Explicit depth requests use partial-book streams. Full-depth JSON
// subscriptions fall through to the REST snapshot + @depth diff path.
let depth_level = match cmd.depth.map(|d| d.get()) {
Some(1..=5) => 5,
Some(6..=10) => 10,
_ => 20,
};View on GitHub (pinned to 18893faf8b)