{"record":{"id":"603b3bc0f7da5cbe","repo":"nautechsystems/nautilus_trader","slug":"instrumentstate-channel-requires-kind-and-currency","errorCode":null,"errorMessage":"InstrumentState channel requires kind and currency parameters, use format_instrument_state_channel() instead","messagePattern":"InstrumentState channel requires kind and currency parameters, use format_instrument_state_channel\\(\\) instead","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/deribit/src/websocket/enums.rs","lineNumber":190,"sourceCode":"            Self::PriceIndex => format!(\"deribit_price_index.{instrument_or_currency}\"),\n            Self::PriceRanking => format!(\"deribit_price_ranking.{instrument_or_currency}\"),\n            Self::VolatilityIndex => format!(\"deribit_volatility_index.{instrument_or_currency}\"),\n            Self::EstimatedExpirationPrice => {\n                format!(\"estimated_expiration_price.{instrument_or_currency}\")\n            }\n            Self::Perpetual => format!(\"perpetual.{instrument_or_currency}.{interval_str}\"),\n            Self::MarkPriceOptions => format!(\"markprice.options.{instrument_or_currency}\"),\n            Self::PlatformState => \"platform_state\".to_string(),\n            Self::Announcements => \"announcements\".to_string(),\n            Self::ChartTrades => format!(\"chart.trades.{instrument_or_currency}.{interval_str}\"),\n            Self::UserOrders => format!(\"user.orders.{instrument_or_currency}.{interval_str}\"),\n            Self::UserTrades => format!(\"user.trades.{instrument_or_currency}.{interval_str}\"),\n            Self::UserPortfolio => format!(\"user.portfolio.{instrument_or_currency}\"),\n            Self::UserChanges => format!(\"user.changes.{instrument_or_currency}.{interval_str}\"),\n            Self::UserAccessLog => \"user.access_log\".to_string(),\n            Self::InstrumentState => {\n                // InstrumentState requires kind and currency, use format_instrument_state_channel() instead\n                panic!(\n                    \"InstrumentState channel requires kind and currency parameters, use format_instrument_state_channel() instead\"\n                )\n            }\n        }\n    }\n\n    /// Formats the instrument status channel for subscription.\n    ///\n    /// Returns the full channel string: `instrument.state.{kind}.{currency}`\n    ///\n    /// # Arguments\n    ///\n    /// * `kind` - Instrument kind: \"future\", \"option\", \"spot\", \"future_combo\", \"option_combo\", or \"any\"\n    /// * `currency` - Currency: \"BTC\", \"ETH\", \"USDC\", \"USDT\", \"EURR\", or \"any\"\n    #[must_use]\n    pub fn format_instrument_state_channel(kind: &str, currency: &str) -> String {\n        format!(\"instrument.state.{kind}.{currency}\")\n    }","sourceCodeStart":172,"sourceCodeEnd":208,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/deribit/src/websocket/enums.rs#L172-L208","documentation":"Deribit's InstrumentState channel is keyed by an instrument kind (e.g. future, option) plus a currency, not by a single instrument name or currency like other channels. The generic format_channel method cannot express those two parameters, so it panics and directs you to the dedicated format_instrument_state_channel() helper. It is a deliberate misuse guard, not a runtime failure.","triggerScenarios":"Calling format_channel(Channel::InstrumentState, ...) with any instrument_or_currency/interval arguments instead of calling format_instrument_state_channel(kind, currency, ...).","commonSituations":"Code builds WebSocket subscription channels generically by iterating over a Channel enum and calling format_channel for every variant; refactors add InstrumentState to the subscription list without special-casing it.","solutions":["Call format_instrument_state_channel() with the kind and currency for InstrumentState subscriptions","Special-case Channel::InstrumentState in generic channel-building code so it routes to the dedicated formatter","Subscribe to a different channel via format_channel if kind/currency granularity was not actually intended"],"exampleFix":"// before\nlet channel = format_channel(Channel::InstrumentState, \"BTC\", \"raw\".into());\n// after\nlet channel = format_instrument_state_channel(InstrumentKind::Future, \"BTC\");","handlingStrategy":"validation","validationCode":"fn build_channel(ch: Channel, instrument: &str, interval: Interval) -> String {\n    match ch {\n        Channel::InstrumentState => format_instrument_state_channel(kind, currency),\n        _ => ch.format_channel(instrument, interval),\n    }\n}","typeGuard":null,"tryCatchPattern":"// Rust panics are not catchable via Result; ensure the channel is not InstrumentState before calling:\nassert_ne!(channel, Channel::InstrumentState, \"use format_instrument_state_channel\");","preventionTips":["Never call format_channel generically over all Channel variants","Route InstrumentState subscriptions through format_instrument_state_channel exclusively","Add a compile-time doc/comment on Channel::InstrumentState pointing to the dedicated formatter","Enumerate channels in config with kind+currency fields when InstrumentState is allowed"],"tags":["rust","panic","websocket","deribit","api-misuse"],"backgroundTag":"unsupported-operation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}