nautechsystems/nautilus_trader · error

Failed to load currencies: {e}

Error message

Failed to load currencies: {e}

What it means

`DatabaseQueries::load_currencies` runs `SELECT * FROM currency ORDER BY id ASC`, decodes each row into a `Currency`, and wraps any sqlx failure in this anyhow error. Failure means execution or decoding failed: connectivity, missing table, or rows containing `currency_type` enum values written by a different version that this binary's decoder cannot understand.

Source

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

            .bind(currency.name.as_str())
            .bind(CurrencyTypePg(currency.currency_type))
            .execute(pool)
            .await
            .map(|_| ())
            .map_err(|e| anyhow::anyhow!("Failed to insert into currency table: {e}"))
    }

    /// Loads all `Currency` entries via the provided `pool`.
    ///
    /// # Errors
    ///
    /// Returns an error if the SELECT operation fails.
    pub async fn load_currencies(pool: &PgPool) -> anyhow::Result<Vec<Currency>> {
        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`.
    ///

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Run matching migrations so the `currency` table and enum values align with this code version.
  2. Align writer/reader versions so all stored currency_type values are decodable, or re-write offending rows with the current version.
  3. Check DATABASE_URL points at the intended cache database.
  4. Read the inner sqlx error to distinguish 'relation does not exist' (migrations) from 'error decoding' (data/schema drift).
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_currencies(&pool).await {
    Err(e) if e.to_string().contains("error decoding") => {
        return Err(anyhow::anyhow!(
            "currency rows unreadable by this version — align writer/reader versions: {e}"
        ));
    }
    result => result?,
}

Prevention

When it happens

Trigger: Calling `DatabaseQueries::load_currencies(pool)` when the connection fails, the `currency` table doesn't exist, or a CurrencyRow fails to decode (e.g. a newer enum variant in the DB that CurrencyTypePg in this version rejects).

Common situations: Version skew: currencies persisted by a newer Nautilus release, then read by an older binary at startup; fresh database without migrations; transient network errors during fetch.

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/31a5490e5820be59. Report an issue: GitHub.