{"record":{"id":"0c12a36fdb09f044","repo":"nautechsystems/nautilus_trader","slug":"binancefuturesdataclient-requires-usdm-or-coinm-pr","errorCode":null,"errorMessage":"BinanceFuturesDataClient requires UsdM or CoinM product type, was {product_type:?}","messagePattern":"BinanceFuturesDataClient requires UsdM or CoinM product type, was (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/binance/src/futures/data.rs","lineNumber":187,"sourceCode":"\nimpl BinanceFuturesDataClient {\n    /// Creates a new [`BinanceFuturesDataClient`] instance.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the client fails to initialize or if the product type\n    /// is not a futures type (UsdM or CoinM).\n    pub fn new(\n        client_id: ClientId,\n        config: BinanceDataClientConfig,\n        product_type: BinanceProductType,\n    ) -> anyhow::Result<Self> {\n        config.validate()?;\n\n        match product_type {\n            BinanceProductType::UsdM | BinanceProductType::CoinM => {}\n            _ => {\n                anyhow::bail!(\n                    \"BinanceFuturesDataClient requires UsdM or CoinM product type, was {product_type:?}\"\n                );\n            }\n        }\n\n        let clock = get_atomic_clock_realtime();\n        let data_sender = get_data_event_sender();\n        let system_sender = try_get_system_event_sender();\n\n        let http_client = BinanceFuturesHttpClient::new(\n            product_type,\n            config.environment,\n            clock,\n            config.api_key.clone(),\n            config.api_secret.clone(),\n            config.base_url_http.clone(),\n            Some(config.recv_window_ms),\n            None, // timeout_secs","sourceCodeStart":169,"sourceCodeEnd":205,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/a4b06ed870971b5671d12754ea138a3ab99b1dec/crates/adapters/binance/src/futures/data.rs#L169-L205","documentation":"BinanceFuturesDataClient::new guards its product_type argument: only UsdM and CoinM are valid because the futures data client wires the fapi/dapi HTTP and WebSocket endpoints. Constructing it directly with Spot, Margin or Options fails this check immediately after config.validate() passes.","triggerScenarios":"Direct construction BinanceFuturesDataClient::new(client_id, config, BinanceProductType::Spot) in Rust code, or a factory/wrapper that routes a product type to the futures client without filtering first. (The standard factory never triggers this because it only forwards UsdM/CoinM.)","commonSituations":"Custom Rust integration on top of the adapter's public constructors; refactoring the factory dispatch and accidentally widening the futures arm; tests that instantiate the futures client with a default (Spot) product type.","solutions":["Pass BinanceProductType::UsdM or ::CoinM to BinanceFuturesDataClient::new.","Route Spot/Margin through BinanceSpotDataClient instead.","Prefer the factories over direct construction; if constructing directly, match on product type first."],"exampleFix":"// before\nlet client = BinanceFuturesDataClient::new(id, config, BinanceProductType::Spot)?;\n\n// after\nlet client = BinanceFuturesDataClient::new(id, config, BinanceProductType::UsdM)?;","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"fn is_futures_product(pt: BinanceProductType) -> bool {\n    matches!(pt, BinanceProductType::UsdM | BinanceProductType::CoinM)\n}","tryCatchPattern":null,"preventionTips":["Construct BinanceFuturesDataClient only with UsdM or CoinM.","Prefer BinanceDataClientFactory, which enforces the routing for you.","In custom wrappers, match on product type and dispatch Spot separately."],"tags":["binance","futures","product-type","constructor-guard","internal-api"],"backgroundTag":"unsupported-product-type","analyzedSha":"a4b06ed870971b5671d12754ea138a3ab99b1dec","analyzedAt":"2026-08-16T22:54:50.089Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}