{"record":{"id":"10400663cb4fe236","repo":"nautechsystems/nautilus_trader","slug":"book-channel-present","errorCode":null,"errorMessage":"book channel present","messagePattern":"book channel present","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/derive/src/data.rs","lineNumber":1905,"sourceCode":"        let mut state = self.registry.state.lock();\n        let removed = state.remove(owner)?;\n        self.dispatch.deactivate(owner, removed.channel_empty);\n        Some(removed)\n    }\n\n    fn has_owners(&self, channel: &str) -> bool {\n        let _guard = self.lock.lock();\n        self.registry.state.lock().has_owners(channel)\n    }\n}\n\nimpl SubscriptionDispatchState {\n    fn activate(&self, owner: ChannelOwner, channel: Option<&str>) {\n        match owner {\n            ChannelOwner::BookDeltas(instrument_id) => {\n                self.active_book_delta_channels.insert(\n                    instrument_id,\n                    channel.expect(\"book channel present\").to_string(),\n                );\n            }\n            ChannelOwner::BookDepth10(instrument_id) => {\n                self.active_book_depth10_channels.insert(\n                    instrument_id,\n                    channel.expect(\"book channel present\").to_string(),\n                );\n            }\n            ChannelOwner::Ticker {\n                instrument_id,\n                feed,\n            } => {\n                self.active_ticker_channels.insert(\n                    instrument_id,\n                    channel.expect(\"ticker channel present\").to_string(),\n                );\n                self.ticker_subscriptions(feed).insert(instrument_id);\n            }","sourceCodeStart":1887,"sourceCodeEnd":1923,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/derive/src/data.rs#L1887-L1923","documentation":"`SubscriptionDispatchState::activate` records which websocket channel (e.g. `summary`, `trades`) owns a subscription. For book-delta and book-depth10 owners it expects the channel string to be present and panics otherwise. The invariant is that book-channel subscriptions are only activated after the channel assignment is known.","triggerScenarios":"Activating a `ChannelOwner::BookDeltas` or `BookDepth10` owner while the `channel` parameter is `None` — i.e. the subscription activation path is invoked before the websocket subscribe confirmation carrying the channel name arrives.","commonSituations":"A websocket reconnect/replay path that re-activates cached book subscriptions without re-deriving their channel names, an out-of-order message where activation precedes the subscribe ack, or a code change adding a new book owner that forgets to pass its channel.","solutions":["Ensure the subscribe-confirmation handler stores the channel name before calling `activate` for book owners.","On reconnect, re-derive the channel (\"book\" / \"depth10\") for book subscriptions rather than passing None.","Change `activate` to accept `&str` for book owners (make the requirement explicit) or fall back to the default channel name instead of panicking."],"exampleFix":"// before\nself.activate(ChannelOwner::BookDeltas(instrument_id), None);\n// after\nself.activate(ChannelOwner::BookDeltas(instrument_id), Some(\"book\"));","handlingStrategy":"validation","validationCode":"// before activate\nif channel.is_none() && matches!(owner, ChannelOwner::BookDeltas(_) | ChannelOwner::BookDepth10(_)) {\n    // defer activation until subscribe confirmation arrives\n    return;\n}","typeGuard":null,"tryCatchPattern":"let result = std::panic::catch_unwind(|| state.activate(owner, channel));\nif result.is_err() { log_and_resubscribe(); }","preventionTips":["Activate book subscriptions only after the subscribe confirmation provides the channel name.","On reconnect, re-derive the channel name for book subscriptions.","Pass a concrete channel string for any new ChannelOwner variants."],"tags":["rust","panic","websocket","invariant"],"backgroundTag":"internal-invariant-violation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}