nautechsystems/nautilus_trader · error · ValueError

account report contains multiple currencies

Error message

account report contains multiple currencies

What it means

With subscribe_race_data enabled, the data client queries the session token a second time (after the main stream is up) to connect the race stream at BETFAIR_RACE_STREAM_HOST, and session_token() returned None. Like error 110, the token slot is filled by login and cleared by disconnect/reconnect, so this indicates the session was cleared mid-connect by a concurrent operation, or the session expired and was invalidated between the two reads.

Source

Thrown at python/nautilus_trader/analysis/tearsheet.py:901

                currency_report["total"].iloc[-1],
            )

    return account_info


def _extract_account_balance_series(
    report: pd.DataFrame,
    target_currency: str | None,
) -> tuple[pd.Series | None, str | None]:
    if report.empty or "currency" not in report or "total" not in report:
        return None, None

    observed_currency: str | None = None

    if target_currency is None:
        account_currencies = set(report["currency"].dropna())
        if len(account_currencies) != 1:
            raise ValueError("account report contains multiple currencies")
        observed_currency = next(iter(account_currencies))
    else:
        report = report[report["currency"] == target_currency]

    if report.empty:
        return None, observed_currency

    totals = pd.to_numeric(report["total"], errors="coerce")
    totals.index = report.index
    totals = totals.dropna().sort_index()
    if totals.empty:
        return None, observed_currency

    return totals.groupby(level=0).last(), observed_currency


def _calculate_daily_balance_returns(total_balance: pd.Series) -> pd.Series | None:
    account_returns = (

View on GitHub (pinned to a4b06ed870)

Solutions

  1. Serialize connect/disconnect: one owner task for the HTTP client lifecycle
  2. Retry connect() to re-login and rebuild both streams
  3. Defer stop/shutdown signals until connect reports completion

Example fix

// before: read once, fail hard
let race_session = self.http_client.session_token().await
    .ok_or_else(|| anyhow::anyhow!("No session token for race stream"))?;

// after: re-login if the slot was cleared
let race_session = match self.http_client.session_token().await {
    Some(t) => t,
    None => {
        self.http_client.reconnect().await?;
        self.http_client.session_token().await
            .ok_or_else(|| anyhow::anyhow!("No session token for race stream"))?
    }
};
Defensive patterns

Strategy: validation

Validate before calling

if config.subscribe_race_data {
    anyhow::ensure!(
        http_client.is_connected().await,
        "session lost before race stream setup; avoid concurrent disconnect during connect"
    );
}

Type guard

async fn has_live_session(client: &BetfairHttpClient) -> bool {
    client.is_connected().await
}

Try / catch

match http_client.session_token().await {
    Some(t) => { /* open race stream */ }
    None => {
        // token cleared mid-connect: re-login and rebuild streams once
        http_client.reconnect().await?;
    }
}

Prevention

When it happens

Trigger: subscribe_race_data: true in the data config and a concurrent disconnect()/reconnect() on the shared HTTP client between main-stream setup and race-stream setup; stopping the node while race stream setup is in progress.

Common situations: Shutdown during startup; supervision timeouts that disconnect mid-connect; racing owners of the shared HTTP client.

Related errors


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