nautechsystems/nautilus_trader · error

Invalid quote rate for pair

Error message

Invalid quote rate for pair {pair}, was {value}

What it means

Raised while converting a map of exchange-rate quotes from `f64` to `Decimal` when `Decimal::from_f64(value)` returns None — i.e. the value is NaN, infinity, or otherwise not representable as a finite decimal. The error names the offending currency pair and the invalid value so the bad quote can be identified.

Solutions

  1. Identify the pair named in the message and fix the upstream source so it returns a finite number instead of NaN/inf.
  2. Filter or sanitize quotes before the conversion: drop or default any pair whose value is not finite (`math.isfinite`).
  3. Check the rate calculation for division by zero (e.g. inverse-rate computation with a zero base).
  4. Ensure the exchange-rate provider is configured with data covering the requested pairs and session times.

Example fix

# before
quotes = provider.get_quotes(pairs)  # may contain NaN
decimals = f64_quotes_to_decimal(quotes)

# after
import math
quotes = {p: v for p, v in provider.get_quotes(pairs).items() if math.isfinite(v)}
if len(quotes) != len(pairs):
    raise ValueError(f"Missing finite quotes for: {pairs - quotes.keys()}")
decimals = f64_quotes_to_decimal(quotes)
Defensive patterns

Strategy: validation

Validate before calling

import math
assert all(math.isfinite(v) for v in quotes.values()), 'quotes contain NaN/inf'

Type guard

def all_finite(quotes: dict) -> bool:
    return all(isinstance(v, float) and math.isfinite(v) for v in quotes.values())

Try / catch

match py_get_exchange_rate(...).await {
    Err(e) if e.to_string().contains("Invalid quote rate") => {
        // sanitize/refresh quotes for the named pair and retry once
    }
    other => other?,
}

Prevention

When it happens

Trigger: Calling `py_get_exchange_rate`, which passes its quotes dict through `f64_quotes_to_decimal` (crates/common/src/python/xrate.rs:69), when any quote value for a pair is NaN, +inf, or -inf — typically produced upstream by division by zero, missing data encoded as NaN, or a misconfigured rate provider.

Common situations: Currency conversion lookups where an exchange-rate provider returns NaN for a pair with no data (illiquid pairs, weekend gaps), custom rate resolvers computing 0/0, or bad cached/stale quote tables containing infinities.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at crates/common/src/python/xrate.rs:69

    let quotes_bid = f64_quotes_to_decimal(quotes_bid).map_err(to_pyvalue_err)?;
    let quotes_ask = f64_quotes_to_decimal(quotes_ask).map_err(to_pyvalue_err)?;

    get_exchange_rate(
        Ustr::from(from_currency),
        Ustr::from(to_currency),
        price_type,
        quotes_bid,
        quotes_ask,
    )
    .map_err(to_pyvalue_err)
}

fn f64_quotes_to_decimal(quotes: HashMap<String, f64>) -> anyhow::Result<AHashMap<Ustr, Decimal>> {
    quotes
        .into_iter()
        .map(|(pair, value)| {
            let rate = Decimal::from_f64(value).ok_or_else(|| {
                anyhow::anyhow!("Invalid quote rate for pair {pair}, was {value}")
            })?;
            Ok((Ustr::from(&pair), rate))
        })
        .collect()
}

View on GitHub (pinned to 18893faf8b)