nautechsystems/nautilus_trader · error

DeriveInstrumentProvider requires at least one currency

Error message

DeriveInstrumentProvider requires at least one currency

What it means

DeriveInstrumentProvider::resolve_load_filters resolves the currency list from load filters or a default, normalizes it, then requires it to be non-empty. An empty currency set would produce no loadable instruments, so the provider refuses with this ensure! error.

Source

Thrown at crates/adapters/derive/src/providers.rs:288

    }
}

fn resolve_load_filters(
    default_currencies: &[String],
    default_expired: bool,
    filters: Option<&HashMap<String, String>>,
) -> anyhow::Result<(Vec<String>, bool)> {
    let currencies = filters
        .and_then(|map| {
            map.get("currency")
                .map(|currency| vec![currency.trim().to_string()])
                .or_else(|| map.get("currencies").map(|value| split_currencies(value)))
        })
        .unwrap_or_else(|| default_currencies.to_vec());

    let currencies = normalize_currencies(currencies);

    anyhow::ensure!(
        !currencies.is_empty(),
        "DeriveInstrumentProvider requires at least one currency",
    );

    let expired = resolve_expired_filter(default_expired, filters)?;

    Ok((currencies, expired))
}

fn resolve_expired_filter(
    default_expired: bool,
    filters: Option<&HashMap<String, String>>,
) -> anyhow::Result<bool> {
    filters
        .and_then(|map| map.get("expired"))
        .map(|value| value.parse::<bool>())
        .transpose()
        .map_err(|e| anyhow::anyhow!("invalid Derive `expired` filter: {e}"))

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Provide at least one currency in the load filters (e.g. "currencies": "ETH")
  2. Set a non-empty default_currencies in the provider/client config
  3. Remove the empty filter key so the default currencies are used

Example fix

// before
let filters = HashMap::from([("currencies".to_string(), "".to_string())]);
provider.load_all(Some(&filters)).await?;
// after
let filters = HashMap::from([("currencies".to_string(), "ETH".to_string())]);
provider.load_all(Some(&filters)).await?;
Defensive patterns

Strategy: validation

Validate before calling

let currencies: Vec<_> = currencies.split(',').map(str::trim).filter(|s| !s.is_empty()).collect();
assert!(!currencies.is_empty(), "at least one currency required for Derive instruments");

Try / catch

match provider.load_all(Some(&filters)).await { Err(e) if e.to_string().contains("requires at least one currency") => provider.load_all(None).await, r => r }

Prevention

When it happens

Trigger: Calling load_all (or provider load) with filters whose `underlying`/`currencies` entries normalize to an empty vector, and no non-empty default_currencies supplied.

Common situations: Passing `currencies: ""` or `underlying: ""` in a filters HashMap; an empty currencies vec configured in a client config; whitespace-only filter values stripped by normalize_currencies.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/32b5af7d419e0691. Report an issue: GitHub.