nautechsystems/nautilus_trader · error

BinanceFuturesDataClient requires UsdM or CoinM product type

Error message

BinanceFuturesDataClient requires UsdM or CoinM product type, was {product_type:?}

What it means

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.

Source

Thrown at crates/adapters/binance/src/futures/data.rs:187

impl BinanceFuturesDataClient {
    /// Creates a new [`BinanceFuturesDataClient`] instance.
    ///
    /// # Errors
    ///
    /// Returns an error if the client fails to initialize or if the product type
    /// is not a futures type (UsdM or CoinM).
    pub fn new(
        client_id: ClientId,
        config: BinanceDataClientConfig,
        product_type: BinanceProductType,
    ) -> anyhow::Result<Self> {
        config.validate()?;

        match product_type {
            BinanceProductType::UsdM | BinanceProductType::CoinM => {}
            _ => {
                anyhow::bail!(
                    "BinanceFuturesDataClient requires UsdM or CoinM product type, was {product_type:?}"
                );
            }
        }

        let clock = get_atomic_clock_realtime();
        let data_sender = get_data_event_sender();
        let system_sender = try_get_system_event_sender();

        let http_client = BinanceFuturesHttpClient::new(
            product_type,
            config.environment,
            clock,
            config.api_key.clone(),
            config.api_secret.clone(),
            config.base_url_http.clone(),
            Some(config.recv_window_ms),
            None, // timeout_secs

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Pass BinanceProductType::UsdM or ::CoinM to BinanceFuturesDataClient::new.
  2. Route Spot/Margin through BinanceSpotDataClient instead.
  3. Prefer the factories over direct construction; if constructing directly, match on product type first.

Example fix

// before
let client = BinanceFuturesDataClient::new(id, config, BinanceProductType::Spot)?;

// after
let client = BinanceFuturesDataClient::new(id, config, BinanceProductType::UsdM)?;
Defensive patterns

Strategy: type-guard

Type guard

fn is_futures_product(pt: BinanceProductType) -> bool {
    matches!(pt, BinanceProductType::UsdM | BinanceProductType::CoinM)
}

Prevention

When it happens

Trigger: 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.)

Common situations: 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.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@a4b06ed870 (2026-08-16). Data as JSON: /api/errors/0c12a36fdb09f044. Report an issue: GitHub.