nautechsystems/nautilus_trader · error

invalid Binance load_ids value {raw:?}: {e}

Error message

invalid Binance load_ids value {raw:?}: {e}

What it means

BinanceDataClientConfig.validate parses every entry of load_ids with InstrumentId::from_str and forwards the parse failure when an entry is malformed. InstrumentId requires the exact 'SYMBOL.VENUE' shape (e.g. 'BTCUSDT.BINANCE'), and the adapter additionally checks the venue is BINANCE.

Source

Thrown at crates/adapters/binance/src/config.rs:97

    /// Returns an error for malformed IDs, unsupported filters, or a legacy
    /// callable filter that Binance v2 cannot execute safely.
    pub fn validate(&self, product_type: BinanceProductType) -> anyhow::Result<()> {
        if let Some(filter_callable) = self
            .filter_callable
            .as_deref()
            .map(str::trim)
            .filter(|value| !value.is_empty())
        {
            anyhow::bail!(
                "Binance v2 does not support instrument filter_callable {filter_callable:?}; \
                 the legacy Binance provider never applied callable filters"
            );
        }

        if let Some(load_ids) = &self.load_ids {
            for raw in load_ids {
                let instrument_id = InstrumentId::from_str(raw)
                    .map_err(|e| anyhow::anyhow!("invalid Binance load_ids value {raw:?}: {e}"))?;
                anyhow::ensure!(
                    instrument_id.venue.as_str() == "BINANCE",
                    "Binance load_ids value {raw:?} must use venue BINANCE"
                );
            }
        }

        for (key, value) in &self.filters {
            let supported = matches!(key.as_str(), "symbols" | "bases" | "quotes")
                || key == "contract_types"
                    && matches!(
                        product_type,
                        BinanceProductType::UsdM | BinanceProductType::CoinM
                    );
            anyhow::ensure!(
                supported,
                "unsupported Binance instrument filter {key:?} for {product_type:?}"
            );

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Use the full 'SYMBOL.VENUE' form: load_ids=['BTCUSDT.BINANCE', 'ETHUSDT.BINANCE'].
  2. For futures perps copy the exact ID from the catalog/logs, e.g. 'BTCUSDT-PERP.BINANCE'; margin instruments carry their own suffix.
  3. If building IDs from parts, format them explicitly (f'{symbol}.BINANCE') and assert the venue suffix before passing the config.

Example fix

# before
load_ids=['BTCUSDT', 'ETH-USDT', ' ']  # missing venue / wrong shape

# after
load_ids=['BTCUSDT.BINANCE', 'ETHUSDT.BINANCE']
Defensive patterns

Strategy: validation

Validate before calling

import re

VALID_ID = re.compile(r'^[A-Z0-9-_]+\.(BINANCE)$')

def valid_load_ids(ids) -> bool:
    return all(isinstance(i, str) and VALID_ID.match(i) for i in ids)

Type guard

def is_binance_instrument_id(value: str) -> bool:
    parts = value.split('.')
    return len(parts) == 2 and parts[1] == 'BINANCE' and bool(parts[0])

Try / catch

try:
    InstrumentId.from_str(raw_id)
except Exception as e:
    raise ValueError(f'load_ids entry {raw_id!r} is not SYMBOL.VENUE: {e}')

Prevention

When it happens

Trigger: Setting load_ids to a value that is not a valid instrument ID string, e.g. 'BTCUSDT' (missing venue), 'BTCUSDT PERP', 'btc_usdt.binance', or an empty/whitespace string, then creating the Binance data or exec client (validate runs in the factory).

Common situations: Generating load_ids from a symbols-only watchlist ('BTCUSDT', 'ETHUSDT'); hand-editing the config and dropping the venue suffix; futures perp IDs where users guess the format instead of copying 'BTCUSDT-PERP.BINANCE' from the ParquetDataCatalog or logs.

Related errors


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