nautechsystems/nautilus_trader · error · anyhow::Error
unsupported Binance instrument filter
Error message
unsupported Binance instrument filter {key:?} for {product_type:?} What it means
BinanceDataClientConfig::instrument_provider filters are restricted to a whitelist. 'symbols', 'bases', and 'quotes' are always supported, while 'contract_types' is only valid for USD-M and COIN-M futures product types. validate() throws this error when an unknown filter key is supplied or when 'contract_types' is used with a non-futures product type (e.g. Spot).
Solutions
- Use only 'symbols', 'bases', or 'quotes' filter keys.
- If using 'contract_types', set product_type to BinanceProductType::UsdM or BinanceProductType::CoinM.
- For Spot product types, remove 'contract_types' from the instrument filters.
- Fix any typos in filter key names.
Example fix
// before
filters.insert("contract_types", json!(["PERPETUAL"])); // product_type: Spot
// after
filters.insert("symbols", json!(["BTCUSDT"])); // or switch product_type to UsdM/CoinM Defensive patterns
Strategy: validation
Validate before calling
const ALLOWED_ALWAYS: [&str; 3] = ["symbols", "bases", "quotes"];
fn filters_valid(filters: &[&str], product_type: BinanceProductType) -> bool {
filters.iter().all(|k| {
ALLOWED_ALWAYS.contains(k)
|| (*k == "contract_types"
&& matches!(product_type, BinanceProductType::UsdM | BinanceProductType::CoinM))
})
} Prevention
- Keep filter keys limited to symbols/bases/quotes unless on USD-M/COIN-M futures.
- Build filters with typed constants instead of raw string literals.
- Share one config-building helper between Spot and futures setups so product-specific keys stay consistent.
When it happens
Trigger: Calling BinanceDataClientConfig::validate() (directly or via request_instruments_with_config) with an instrument_provider config whose filters map contains a key other than symbols/bases/quotes, or containing 'contract_types' while product_type is Spot or another non-futures BinanceProductType.
Common situations: Copying a futures config example into a Spot client setup; typo'd filter keys like 'base' or 'symbol'; forward-porting config from a version that accepted more filter keys.
Related errors
- Binance instrument filter
- Binance load_ids value
- invalid Binance load_ids value
- recv_window_ms must be in the inclusive range 1..=60000, was
- ws_trading_setup_timeout_ms must be greater than 0, was
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/8685c10cbb17c249.
Report an issue: GitHub.
Appendix: source
Thrown at crates/adapters/binance/src/config.rs:115
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:?}"
);
validate_filter_strings(key, value)?;
}
Ok(())
}
}
fn validate_filter_strings(name: &str, value: &serde_json::Value) -> anyhow::Result<()> {
let valid = match value {
serde_json::Value::String(value) => !value.trim().is_empty(),
serde_json::Value::Array(values) => {
!values.is_empty()
&& values
.iter()
.all(|value| value.as_str().is_some_and(|value| !value.trim().is_empty()))View on GitHub (pinned to 18893faf8b)