{"record":{"id":"2f40b26285078073","repo":"nautechsystems/nautilus_trader","slug":"invalid-quote-rate-for-pair-pair-was-value","errorCode":null,"errorMessage":"Invalid quote rate for pair {pair}, was {value}","messagePattern":"Invalid quote rate for pair (.+?), was (.+?)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/common/src/python/xrate.rs","lineNumber":69,"sourceCode":"    let quotes_bid = f64_quotes_to_decimal(quotes_bid).map_err(to_pyvalue_err)?;\n    let quotes_ask = f64_quotes_to_decimal(quotes_ask).map_err(to_pyvalue_err)?;\n\n    get_exchange_rate(\n        Ustr::from(from_currency),\n        Ustr::from(to_currency),\n        price_type,\n        quotes_bid,\n        quotes_ask,\n    )\n    .map_err(to_pyvalue_err)\n}\n\nfn f64_quotes_to_decimal(quotes: HashMap<String, f64>) -> anyhow::Result<AHashMap<Ustr, Decimal>> {\n    quotes\n        .into_iter()\n        .map(|(pair, value)| {\n            let rate = Decimal::from_f64(value).ok_or_else(|| {\n                anyhow::anyhow!(\"Invalid quote rate for pair {pair}, was {value}\")\n            })?;\n            Ok((Ustr::from(&pair), rate))\n        })\n        .collect()\n}\n","sourceCodeStart":51,"sourceCodeEnd":75,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/common/src/python/xrate.rs#L51-L75","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Identify the pair named in the message and fix the upstream source so it returns a finite number instead of NaN/inf.","Filter or sanitize quotes before the conversion: drop or default any pair whose value is not finite (`math.isfinite`).","Check the rate calculation for division by zero (e.g. inverse-rate computation with a zero base).","Ensure the exchange-rate provider is configured with data covering the requested pairs and session times."],"exampleFix":"# before\nquotes = provider.get_quotes(pairs)  # may contain NaN\ndecimals = f64_quotes_to_decimal(quotes)\n\n# after\nimport math\nquotes = {p: v for p, v in provider.get_quotes(pairs).items() if math.isfinite(v)}\nif len(quotes) != len(pairs):\n    raise ValueError(f\"Missing finite quotes for: {pairs - quotes.keys()}\")\ndecimals = f64_quotes_to_decimal(quotes)","handlingStrategy":"validation","validationCode":"import math\nassert all(math.isfinite(v) for v in quotes.values()), 'quotes contain NaN/inf'","typeGuard":"def all_finite(quotes: dict) -> bool:\n    return all(isinstance(v, float) and math.isfinite(v) for v in quotes.values())","tryCatchPattern":"match py_get_exchange_rate(...).await {\n    Err(e) if e.to_string().contains(\"Invalid quote rate\") => {\n        // sanitize/refresh quotes for the named pair and retry once\n    }\n    other => other?,\n}","preventionTips":["Sanitize provider output with math.isfinite before use","Guard rate math against division by zero","Verify rate providers cover all requested pairs and sessions","Refresh stale cached quote tables"],"tags":["decimal","conversion","nan","exchange-rate","validation"],"backgroundTag":"invalid-argument-value","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}