nautechsystems/nautilus_trader · error · anyhow::Error

Missing field '{field}' in filter

Error message

Missing field '{field}' in filter

What it means

While extracting parameters from a Binance exchangeInfo filter object (PRICE_FILTER, LOT_SIZE, MIN_NOTIONAL, ...), the expected string field named in the message (tickSize, stepSize, notional, ...) is absent or not a string. The filter JSON does not match the schema the parser expects.

Source

Thrown at crates/adapters/binance/src/common/parse.rs:153

    Currency::get_or_create_crypto(code)
}

/// Extracts filter values from Binance symbol filters array.
fn get_filter<'a>(filters: &'a [Value], filter_type: &str) -> Option<&'a Value> {
    filters.iter().find(|f| {
        f.get("filterType")
            .and_then(|v| v.as_str())
            .is_some_and(|t| t == filter_type)
    })
}

/// Parses a string field from a JSON value.
fn parse_filter_string(filter: &Value, field: &str) -> anyhow::Result<String> {
    filter
        .get(field)
        .and_then(|v| v.as_str())
        .map(String::from)
        .ok_or_else(|| anyhow::anyhow!("Missing field '{field}' in filter"))
}

/// Parses a Price from a filter field.
fn parse_filter_price(filter: &Value, field: &str) -> anyhow::Result<Price> {
    let value = parse_filter_string(filter, field)?;
    Price::from_str(&value).map_err(|e| anyhow::anyhow!("Failed to parse {field}='{value}': {e}"))
}

/// Parses a Quantity from a filter field.
fn parse_filter_quantity(filter: &Value, field: &str) -> anyhow::Result<Quantity> {
    let value = parse_filter_string(filter, field)?;
    Quantity::from_str(&value)
        .map_err(|e| anyhow::anyhow!("Failed to parse {field}='{value}': {e}"))
}

/// Parses the futures `MIN_NOTIONAL` filter into a `Money` value in `currency`.
///
/// Returns `None` when the filter is absent, the `notional` field cannot be

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Update the Binance adapter to the latest release tracking the current exchangeInfo schema
  2. Capture the raw exchangeInfo response, confirm which filter lacks the field, and report it to maintainers
  3. Bypass any proxy/gateway that rewrites instrument responses while loading instruments

Example fix

// before: assuming the field always exists
let tick = parse_filter_string(&filter, "tickSize")?;

// after: tolerate schema drift explicitly
let tick = parse_filter_string(&filter, "tickSize")
    .with_context(|| format!("filter schema drift: {filter:?}"))?;
Defensive patterns

Strategy: validation

Validate before calling

fn filter_has_string_field(filter: &serde_json::Value, field: &str) -> bool {
    filter.get(field).is_some_and(|v| v.is_string())
}
// check required fields per filter type before parsing, e.g. PRICE_FILTER: tickSize/minPrice/maxPrice

Type guard

fn is_wellformed_price_filter(f: &serde_json::Value) -> bool {
    ["tickSize", "minPrice", "maxPrice"].iter().all(|k| f.get(k).is_some_and(|v| v.is_string()))
}

Try / catch

let tick = parse_filter_string(&filter, "tickSize")
    .with_context(|| format!("unexpected exchangeInfo filter schema: {filter:?}"))?;

Prevention

When it happens

Trigger: Binance changes or extends a filter's field set, introduces a new filter type reusing known filterType tags with different fields, or an intermediate proxy/gateway mangles the exchangeInfo response.

Common situations: Adapter version older than a live exchangeInfo schema change; custom API gateways rewriting responses; replayed captures from a schema transition period.

Related errors


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