nautechsystems/nautilus_trader · error

Binance instrument filter {name:?} must be a non-empty strin

Error message

Binance instrument filter {name:?} must be a non-empty string or array of strings

What it means

validate_filter_strings requires each instrument filter value to be a single non-empty string, or a non-empty JSON array whose elements are all non-empty strings. Numbers, booleans, objects, null, an empty array, or whitespace-only strings all fail this check before the provider starts.

Source

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

        }

        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()))
        }
        _ => false,
    };

    anyhow::ensure!(
        valid,
        "Binance instrument filter {name:?} must be a non-empty string or array of strings"
    );
    Ok(())
}

/// Spot market-data transport mode.
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Serialize, Deserialize)]
#[cfg_attr(
    feature = "python",
    pyo3::pyclass(module = "nautilus_trader.adapters.binance", eq, from_py_object)
)]
#[cfg_attr(
    feature = "python",
    pyo3_stub_gen::derive::gen_stub_pyclass_enum(module = "nautilus_trader.adapters.binance")
)]
pub enum BinanceSpotMarketDataMode {
    #[default]

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Make every filter value a non-empty string or a list of non-empty strings, e.g. filters={'bases': ['BTC', 'ETH']} or filters={'quotes': 'USDT'}.
  2. Sanitize programmatic values: [str(v).strip() for v in values if str(v).strip()].
  3. Validate the config immediately after construction so the error names the offending filter key early.

Example fix

# before (int elements / empty values)
filters={'symbols': [1100, 'BTCUSDT', '']}

# after
filters={'symbols': ['1100ETH', 'BTCUSDT']}
Defensive patterns

Strategy: validation

Validate before calling

def clean_filter_values(values):
    if isinstance(values, str):
        values = [values]
    cleaned = [str(v).strip() for v in values if str(v).strip()]
    assert cleaned, 'filter must have at least one non-empty string'
    return cleaned

cfg.filters = {k: clean_filter_values(v) for k, v in cfg.filters.items()}

Type guard

def is_valid_filter_value(v) -> bool:
    if isinstance(v, str):
        return bool(v.strip())
    if isinstance(v, list):
        return bool(v) and all(isinstance(x, str) and x.strip() for x in v)
    return False

Prevention

When it happens

Trigger: Setting filters={'bases': ['BTC', 42]} (mixed types), filters={'quotes': 'USDT '.trim() is fine but ' ' is not}, filters={'symbols': []} (empty array), or filters={'bases': {'m': 'main'}} (object) in the instrument provider config; then config.validate() at client creation rejects it.

Common situations: Generating filter lists from YAML/JSON config files where values deserialize as numbers (symbol '1100' as int); environment-variable-driven configs that yield empty strings; a typo'd nested dict instead of a flat list.

Related errors


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