nautechsystems/nautilus_trader · critical · anyhow::Error

BinanceFuturesExecutionClient requires UsdM or CoinM product

Error message

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

What it means

BinanceFuturesExecutionClient::new rejects any product type other than UsdM and CoinM, bailing after config.validate() succeeds. The futures client drives /fapi (USD-margined) or /dapi (coin-margined) endpoints and cannot operate on spot instruments, so a Spot (or other) product type is a hard startup failure. resolve_credentials and all later wiring only run for the two futures product types.

Source

Thrown at crates/adapters/binance/src/futures/execution.rs:244

    recovery_tx: Option<tokio::sync::mpsc::UnboundedSender<()>>,
    pending_tasks: TaskHandles,
    is_hedge_mode: AtomicBool,
}

impl BinanceFuturesExecutionClient {
    /// Creates a new [`BinanceFuturesExecutionClient`].
    ///
    /// # Errors
    ///
    /// Returns an error if the HTTP client fails to initialize, credentials are
    /// missing, or the product type is not a futures type (UsdM or CoinM).
    pub fn new(core: ExecutionClientCore, config: BinanceExecClientConfig) -> anyhow::Result<Self> {
        config.validate()?;
        let product_type = config.product_type;
        match product_type {
            BinanceProductType::UsdM | BinanceProductType::CoinM => {}
            _ => {
                anyhow::bail!(
                    "BinanceFuturesExecutionClient requires UsdM or CoinM product type, was {product_type:?}"
                );
            }
        }

        let (api_key, api_secret) = resolve_credentials(
            config.api_key.clone(),
            config.api_secret.clone(),
            config.environment,
            product_type,
        )?;

        let clock = get_atomic_clock_realtime();

        let http_client = BinanceFuturesHttpClient::new(
            product_type,
            config.environment,
            clock,

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Set product_type: UsdM (USDT-margined) or CoinM (coin-margined) in the futures execution client config
  2. If spot trading is intended, use the Binance spot execution client instead of the futures one
  3. Audit any factory/routing layer that selects the futures client by venue alone

Example fix

// before
let config = BinanceExecClientConfig { product_type: BinanceProductType::Spot, ..Default::default() };
let client = BinanceFuturesExecutionClient::new(core, config)?;

// after
let config = BinanceExecClientConfig { product_type: BinanceProductType::UsdM, ..Default::default() };
let client = BinanceFuturesExecutionClient::new(core, config)?;
Defensive patterns

Strategy: validation

Validate before calling

use binance common::enums::BinanceProductType; // adapter's enum

let product_type = config.product_type;
anyhow::ensure!(
    matches!(product_type, BinanceProductType::UsdM | BinanceProductType::CoinM),
    "futures client needs UsdM/CoinM, got {product_type:?}"
);
let client = BinanceFuturesExecutionClient::new(core, config)?;

Type guard

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

Prevention

When it happens

Trigger: Constructing the futures execution client with a BinanceExecClientConfig whose product_type is Spot (including the config default), typically via a factory or node config that reused the spot adapter's settings.

Common situations: Copy-pasted Binance config blocks between the spot and futures sections of a node config; YAML/TOML missing the product_type override so it defaults to Spot; a routing layer mapping venue BINANCE to the futures client regardless of product type.

Related errors


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