nautechsystems/nautilus_trader · error

Failed to load currency: {e}

Error message

Failed to load currency: {e}

What it means

`DatabaseQueries::load_currency` runs `SELECT * FROM currency WHERE id = $1` and returns Ok(None) when no row matches — a missing currency is not an error. This anyhow error is raised only on execution or row-decoding failure: connection loss, missing table (migrations not applied), or a stored row that can't decode into CurrencyRow.

Source

Thrown at crates/infrastructure/src/sql/queries.rs:142

        sqlx::query_as::<_, CurrencyRow>("SELECT * FROM currency ORDER BY id ASC")
            .fetch_all(pool)
            .await
            .map(|rows| rows.into_iter().map(|row| row.0).collect())
            .map_err(|e| anyhow::anyhow!("Failed to load currencies: {e}"))
    }

    /// Loads a single `Currency` entry by `code` via the provided `pool`.
    ///
    /// # Errors
    ///
    /// Returns an error if the SELECT operation fails.
    pub async fn load_currency(pool: &PgPool, code: &str) -> anyhow::Result<Option<Currency>> {
        sqlx::query_as::<_, CurrencyRow>("SELECT * FROM currency WHERE id = $1")
            .bind(code)
            .fetch_optional(pool)
            .await
            .map(|currency| currency.map(|row| row.0))
            .map_err(|e| anyhow::anyhow!("Failed to load currency: {e}"))
    }

    /// Inserts or updates an `InstrumentAny` entry via the provided `pool`.
    ///
    /// # Errors
    ///
    /// Returns an error if the INSERT or UPDATE operation fails.
    pub async fn add_instrument(
        pool: &PgPool,
        kind: &str,
        instrument: Box<dyn Instrument>,
    ) -> anyhow::Result<()> {
        sqlx::query(r#"
            INSERT INTO "instrument" (
                id, kind, raw_symbol, base_currency, underlying, quote_currency, settlement_currency, isin, asset_class, exchange,
                strategy_type, multiplier, option_kind, is_inverse, strike_price, activation_ns, expiration_ns, price_precision, size_precision,
                price_increment, size_increment, maker_fee, taker_fee, margin_init, margin_maint, lot_size, max_quantity, min_quantity, max_notional,
                min_notional, max_price, min_price, ts_init, ts_event, created_at, updated_at

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Run migrations so the `currency` table exists with matching enum types.
  2. If the inner error is a decode failure, align versions or re-write the offending row with the current binary.
  3. Verify pool connectivity and privileges.
  4. Handle the Option<Currency> None case separately — absent rows are not this error.
Defensive patterns

Strategy: try-catch

Validate before calling

let exists: bool = sqlx::query_scalar(
    "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'currency')",
).fetch_one(pool).await?;
if !exists {
    return Err(anyhow::anyhow!("'currency' table missing — run migrations"));
}

Try / catch

match DatabaseQueries::load_currency(&pool, code).await {
    Ok(None) => {
        tracing::debug!("currency {code} not cached");
    }
    Err(e) if e.to_string().contains("relation \"currency\" does not exist") => {
        return Err(anyhow::anyhow!("cache schema missing — run migrations: {e}"));
    }
    result => result?,
}

Prevention

When it happens

Trigger: Calling `DatabaseQueries::load_currency(pool, code)` when the connection fails, the `currency` table doesn't exist, or the row's `currency_type` (or other column) can't decode — e.g. an enum value written by a different version.

Common situations: Fresh database without migrations; version skew between the process that wrote the currency row and the reader; transient connection loss during a lookup.

Understand the failure class

Background: Database query failed: Internal Server Error 500s wrapping SQL, Prisma, and connection failures — what to check first — this error's family across 16 libraries.

Related errors


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