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
- Run the current migrations so the `instrument` table matches this code version's columns and enum types.
- Read the Debug-formatted wrapped sqlx error to find the failing column/value and fix the data or migrate the schema.
- Validate the instrument's field ranges (precisions, fees, prices) before persisting; adjust numeric column types if values legitimately overflow.
- 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
- Keep instrument table migrations synchronized with application upgrades.
- Validate instrument field ranges (precisions, fees, prices, strike) before persistence to avoid numeric overflow.
- Test persisting each instrument kind you use against a migrated database.
- Log the Debug-formatted sqlx error — it names the exact failing column or cast.
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
- Failed to insert into block table: {e}
- Failed to batch insert into block table: {e}
- Failed to batch insert into pool_event_block table: {e}
- Failed to insert into dex table: {e}
- Failed to insert into pool table: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/c1fae13f74e76ab1.
Report an issue: GitHub.