nautechsystems/nautilus_trader · error · anyhow::Error

No currency_code in account details

Error message

No currency_code in account details

What it means

getAccountDetails succeeded but the response deserialized with currency_code None. The adapter requires the currency to build Currency values for money/price conversion and refuses to guess, so it errors. A well-formed Betfair response always carries currencyCode, so this points to an unexpected or transformed response body.

Source

Thrown at crates/adapters/betfair/src/provider.rs:405

    pub fn min_notional(&self) -> Option<Money> {
        self.min_notional
    }

    /// Fetches the account currency from the Betfair Account API.
    ///
    /// # Errors
    ///
    /// Returns an error if the API call fails or the currency code is missing/unknown.
    pub async fn get_account_currency(&self) -> anyhow::Result<Currency> {
        let details: AccountDetailsResponse = self
            .http_client
            .send_accounts(METHOD_GET_ACCOUNT_DETAILS, &serde_json::json!({}))
            .await
            .map_err(|e| anyhow::anyhow!("{e}"))?;

        let code = details
            .currency_code
            .ok_or_else(|| anyhow::anyhow!("No currency_code in account details"))?;
        Ok(code.as_str().parse::<Currency>()?)
    }

    /// Builds an effective filter by merging runtime overrides with the base filter.
    fn build_effective_filter(
        &self,
        overrides: Option<&HashMap<String, String>>,
    ) -> NavigationFilter {
        let Some(overrides) = overrides else {
            return self.nav_filter.clone();
        };

        let parse_csv = |key: &str| -> Option<Vec<String>> {
            overrides
                .get(key)
                .map(|v| v.split(',').map(|s| s.trim().to_string()).collect())
        };

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Set currency explicitly in the config so the lookup is skipped entirely.
  2. Inspect the raw getAccountDetails response to see what actually came back.
  3. Report the payload shape to the adapter maintainers.

Example fix

// before: rely on auto-detection
let config = BetfairDataConfig::default();

// after: pin the currency, skip getAccountDetails
let config = BetfairDataConfig {
    currency: Some(Currency::from_str("GBP").unwrap()),
    ..Default::default()
};
Defensive patterns

Strategy: fallback

Try / catch

let currency = match provider.get_account_currency().await {
    Ok(c) => c,
    Err(e) if e.to_string().contains("No currency_code") => {
        log::warn!("currency_code missing from account details; using configured fallback");
        config_currency // from BetfairExecConfig/BetfairDataConfig
    }
    Err(e) => return Err(e),
};

Prevention

When it happens

Trigger: The accounts endpoint returning a payload lacking currencyCode — an API change, an intermediary/proxy rewriting the response, or a deserialization mismatch in the adapter's models.

Common situations: Version drift between the adapter's response models and the live API; corporate proxies stripping response fields.

Related errors


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