nautechsystems/nautilus_trader · error

Failed to insert item {} into instrument table: {:?}

Error message

Failed to insert item {} into instrument table: {:?}

What it means

`DatabaseQueries::add_instrument` performs a 34-parameter upsert (`INSERT ... ON CONFLICT (id) DO UPDATE`) into the `instrument` table, including Postgres enum casts (asset_class, option_kind) and many numeric/string-encoded domain values, and wraps any sqlx failure in this anyhow error with the instrument id. Failures typically indicate a missing table, an unrepresentable enum or column value, numeric overflow, or a NULL bound to a NOT NULL column.

Source

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

            .bind(instrument.price_increment().to_string())
            .bind(instrument.size_increment().to_string())
            .bind(instrument.maker_fee().to_string())
            .bind(instrument.taker_fee().to_string())
            .bind(instrument.margin_init().to_string())
            .bind(instrument.margin_maint().to_string())
            .bind(instrument.lot_size().map(|x| x.to_string()))
            .bind(instrument.max_quantity().map(|x| x.to_string()))
            .bind(instrument.min_quantity().map(|x| x.to_string()))
            .bind(instrument.max_notional().map(|x| x.to_string()))
            .bind(instrument.min_notional().map(|x| x.to_string()))
            .bind(instrument.max_price().map(|x| x.to_string()))
            .bind(instrument.min_price().map(|x| x.to_string()))
            .bind(instrument.ts_init().to_string())
            .bind(instrument.ts_event().to_string())
            .execute(pool)
            .await
            .map(|_| ())
            .map_err(|e| anyhow::anyhow!("Failed to insert item {} into instrument table: {:?}", instrument.id(), e))
    }

    /// Loads a single `InstrumentAny` entry by `instrument_id` via the provided `pool`.
    ///
    /// # Errors
    ///
    /// Returns an error if the SELECT operation fails.
    pub async fn load_instrument(
        pool: &PgPool,
        instrument_id: &InstrumentId,
    ) -> anyhow::Result<Option<InstrumentAny>> {
        sqlx::query_as::<_, InstrumentAnyRow>("SELECT * FROM instrument WHERE id = $1")
            .bind(instrument_id.to_string())
            .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}")

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Run the current migrations so the `instrument` table matches this code version's columns and enum types.
  2. Read the Debug-formatted wrapped sqlx error to find the failing column/value and fix the data or migrate the schema.
  3. Validate the instrument's field ranges (precisions, fees, prices) before persisting; adjust numeric column types if values legitimately overflow.
  4. Verify connectivity and INSERT/UPDATE privileges on the `instrument` table.

Example fix

// before
DatabaseQueries::add_instrument(&pool, "currency", &instrument).await?;
// after
if let Err(e) = DatabaseQueries::add_instrument(&pool, "currency", &instrument).await {
    tracing::error!("instrument {} upsert failed: {e:?}", instrument.id());
    return Err(e);
}
Defensive patterns

Strategy: try-catch

Validate before calling

let ready: bool = sqlx::query_scalar(
    "SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'instrument') \
     AND EXISTS (SELECT 1 FROM pg_type WHERE typname = 'asset_class')",
).fetch_one(pool).await?;
if !ready {
    return Err(anyhow::anyhow!("instrument schema missing — run migrations"));
}

Try / catch

if let Err(e) = DatabaseQueries::add_instrument(&pool, kind, &instrument).await {
    tracing::error!("instrument {} upsert failed: {e:?}", instrument.id());
    // inspect e for the failing column: null violation / numeric overflow / enum cast
    return Err(anyhow::anyhow!("persisting {}: {e}", instrument.id()));
}

Prevention

When it happens

Trigger: Calling `DatabaseQueries::add_instrument(pool, kind, instrument)` when: migrations weren't run (table or enum types missing); the `asset_class` cast fails; a value such as strike_price, multiplier, or fees overflows its numeric column; a NOT NULL column receives a null binding; connectivity drops mid-write.

Common situations: Schema/code version mismatch for instrument kinds or enum values; instruments with unusual field values (extreme precision, huge multipliers) tripping column limits; stale databases from prior releases; restricted DB role.

Related errors


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