nautechsystems/nautilus_trader · error

Failed to load instruments: {e}

Error message

Failed to load instruments: {e}

What it means

This error is raised by `load_instruments` in the SQL queries module when the `SELECT * FROM instrument` query against PostgreSQL fails. The library wraps any sqlx error returned by `fetch_all` into an `anyhow::Error` with this message, so the underlying cause (connection issue, missing table, bad column mapping) is embedded in the `{e}` text. It means the instruments could not be read from the database, and the caller receives no instrument data.

Source

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

            .fetch_optional(pool)
            .await
            .map(|instrument| instrument.map(|row| row.0))
            .map_err(|e| {
                anyhow::anyhow!("Failed to load instrument with id {instrument_id},error is: {e}")
            })
    }

    /// Loads all `InstrumentAny` entries via the provided `pool`.
    ///
    /// # Errors
    ///
    /// Returns an error if the SELECT operation fails.
    pub async fn load_instruments(pool: &PgPool) -> anyhow::Result<Vec<InstrumentAny>> {
        sqlx::query_as::<_, InstrumentAnyRow>("SELECT * FROM instrument")
            .fetch_all(pool)
            .await
            .map(|rows| rows.into_iter().map(|row| row.0).collect())
            .map_err(|e| anyhow::anyhow!("Failed to load instruments: {e}"))
    }

    /// Inserts or replaces an `InstrumentClose`.
    ///
    /// # Errors
    ///
    /// Returns an error if the SQL INSERT or UPDATE fails.
    pub async fn add_instrument_close(
        pool: &PgPool,
        close: &InstrumentClose,
    ) -> anyhow::Result<()> {
        sqlx::query(
            r#"
            INSERT INTO "instrument_close" (
                instrument_id, close_price, close_type, ts_event, ts_init, created_at
            ) VALUES ($1, $2, $3, $4, $5, CURRENT_TIMESTAMP)
            ON CONFLICT (instrument_id) DO UPDATE
            SET close_price = EXCLUDED.close_price,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect the wrapped `{e}` message to identify the root cause (connection vs missing table vs decode error).
  2. Run the project's SQL migrations so the `instrument` table exists with the expected schema.
  3. Verify the PostgreSQL connection string / pool configuration and that the database is reachable.
  4. If it is a decode/type error, align the database column types with `InstrumentAnyRow` (upgrade schema or crate together).

Example fix

// before: calls the query and panics/unwraps elsewhere
let instruments = load_instruments(&pool).await.unwrap();

// after: handle the error explicitly
let instruments = match load_instruments(&pool).await {
    Ok(v) => v,
    Err(e) => {
        tracing::error!("instrument load failed: {e:#}");
        return Err(e);
    }
};
Defensive patterns

Strategy: try-catch

Validate before calling

// Before calling: verify DB reachable and table exists
let ok = sqlx::query_scalar::<_, i64>(
    "SELECT COUNT(*) FROM information_schema.tables WHERE table_name = 'instrument'")
    .fetch_one(pool).await? > 0;
if !ok { return Err(anyhow::anyhow!("instrument table missing: run migrations")); }

Try / catch

match load_instruments(&pool).await {
    Ok(instruments) => instruments,
    Err(e) => {
        tracing::error!("load_instruments failed: {e:#}");
        return Err(anyhow::anyhow!("instruments unavailable: {e:#}"));
    }
}

Prevention

When it happens

Trigger: Calling `load_instruments(&pool)` when: the database connection is down or the pool is exhausted; the `instrument` table does not exist (migrations not run); a column type in the table does not match `InstrumentAnyRow`'s expected types (sqlx decode failure); or the query times out.

Common situations: Running against a database without the Nautilus schema migrations applied; wrong DATABASE_URL pointing at an empty/unrelated database; schema drift after upgrading the crate where a new/renamed column breaks the row decoding; PostgreSQL temporarily unreachable in a containerized environment.

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