{"record":{"id":"4568a118e05cacc0","repo":"nautechsystems/nautilus_trader","slug":"cannot-subscribe-l1-mbp-and-l2-mbp-for-the-same-bi","errorCode":null,"errorMessage":"cannot subscribe L1_MBP and L2_MBP for the same Binance Futures instrument","messagePattern":"cannot subscribe L1_MBP and L2_MBP for the same Binance Futures instrument","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/binance/src/futures/data.rs","lineNumber":1919,"sourceCode":"            \"subscribe_instruments: Binance Futures instruments are fetched via HTTP on connect\"\n        );\n        Ok(())\n    }\n\n    fn subscribe_instrument(&mut self, _cmd: SubscribeInstrument) -> anyhow::Result<()> {\n        log::debug!(\n            \"subscribe_instrument: Binance Futures instruments are fetched via HTTP on connect\"\n        );\n        Ok(())\n    }\n\n    fn subscribe_book_deltas(&mut self, cmd: SubscribeBookDeltas) -> anyhow::Result<()> {\n        if cmd.book_type == BookType::L1_MBP {\n            anyhow::ensure!(\n                cmd.depth.is_none_or(|depth| depth.get() == 1),\n                \"Binance Futures L1_MBP supports depth 1 only\"\n            );\n            anyhow::ensure!(\n                !self.book_subscriptions.contains_key(&cmd.instrument_id),\n                \"cannot subscribe L1_MBP and L2_MBP for the same Binance Futures instrument\"\n            );\n            self.l1_book_subscriptions.rcu(|subscriptions| {\n                *subscriptions.entry(cmd.instrument_id).or_insert(0) += 1;\n            });\n            self.subscribe_top_of_book(cmd.instrument_id);\n            return Ok(());\n        }\n\n        if cmd.book_type != BookType::L2_MBP {\n            anyhow::bail!(\"Binance Futures supports L1_MBP and L2_MBP order book subscriptions\");\n        }\n        anyhow::ensure!(\n            !self.l1_book_subscriptions.contains_key(&cmd.instrument_id),\n            \"cannot subscribe L1_MBP and L2_MBP for the same Binance Futures instrument\"\n        );\n","sourceCodeStart":1901,"sourceCodeEnd":1937,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/crates/adapters/binance/src/futures/data.rs#L1901-L1937","documentation":"The adapter tracks L2_MBP subscriptions in `book_subscriptions` and L1_MBP refcounts in `l1_book_subscriptions`, and refuses to mix book types per instrument. This instance fires when an L1_MBP subscribe arrives while `book_subscriptions` already contains the same instrument_id (an active L2 subscription). The ambiguous state is rejected before any stream is opened.","triggerScenarios":"Subscribing L1_MBP book deltas for an instrument that currently has an active L2_MBP book-deltas subscription (e.g. subscribe L2 depth=20 first, then L1 for the same instrument_id).","commonSituations":"A strategy module subscribing top-of-book while another module (or an indicator) already holds an L2 book for the same instrument; switching book types at runtime without unsubscribing; duplicated actors subscribing the same instrument with different configs.","solutions":["Unsubscribe the existing L2_MBP book deltas for the instrument before subscribing L1_MBP","Or keep the existing L2 subscription — depth-1 like behaviour can be derived from an L2 book","Centralise book subscriptions per instrument in one component so conflicting types cannot race"],"exampleFix":"# before: L2 already active for instrument_id\nactor.subscribe_order_book_deltas(instrument_id, book_type=BookType.L1_MBP, depth=None)  # fails\n\n# after: unsubscribe L2 first, then subscribe L1\nactor.unsubscribe_order_book_deltas(instrument_id)\nactor.subscribe_order_book_deltas(instrument_id, book_type=BookType.L1_MBP, depth=None)","handlingStrategy":"validation","validationCode":"active_book_types: dict = {}  # instrument_id -> 'L1' | 'L2', track what you subscribed\n\ndef subscribe_book_deltas_checked(actor, instrument_id, book_type, depth=None):\n    current = active_book_types.get(instrument_id)\n    if current and current != ('L1' if book_type == BookType.L1_MBP else 'L2'):\n        raise ValueError(\n            f'{instrument_id} already has an {current} subscription; unsubscribe it before switching book type'\n        )\n    actor.subscribe_order_book_deltas(instrument_id, book_type=book_type, depth=depth)\n    active_book_types[instrument_id] = 'L1' if book_type == BookType.L1_MBP else 'L2'","typeGuard":null,"tryCatchPattern":"try:\n    actor.subscribe_order_book_deltas(instrument_id, book_type=BookType.L1_MBP, depth=None)\nexcept Exception as e:\n    if 'cannot subscribe L1_MBP and L2_MBP' in str(e):\n        actor.unsubscribe_order_book_deltas(instrument_id)  # drop the L2 sub, then retry once\n        actor.subscribe_order_book_deltas(instrument_id, book_type=BookType.L1_MBP, depth=None)\n    else:\n        raise","preventionTips":["One book type per instrument across the whole node — coordinate between actors/modules","Unsubscribe before switching L1/L2 for the same instrument","Derive top-of-book from your L2 book instead of holding both subscriptions"],"tags":["binance","futures","orderbook","subscription-conflict","l1-mbp","l2-mbp"],"backgroundTag":"conflicting-orderbook-subscription","analyzedSha":"a4b06ed870971b5671d12754ea138a3ab99b1dec","analyzedAt":"2026-08-16T22:54:50.089Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}