{"record":{"id":"c1fae13f74e76ab1","repo":"nautechsystems/nautilus_trader","slug":"failed-to-insert-item-into-instrument-table","errorCode":null,"errorMessage":"Failed to insert item {} into instrument table: {:?}","messagePattern":"Failed to insert item (.+?) into instrument table: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/infrastructure/src/sql/queries.rs","lineNumber":207,"sourceCode":"            .bind(instrument.price_increment().to_string())\n            .bind(instrument.size_increment().to_string())\n            .bind(instrument.maker_fee().to_string())\n            .bind(instrument.taker_fee().to_string())\n            .bind(instrument.margin_init().to_string())\n            .bind(instrument.margin_maint().to_string())\n            .bind(instrument.lot_size().map(|x| x.to_string()))\n            .bind(instrument.max_quantity().map(|x| x.to_string()))\n            .bind(instrument.min_quantity().map(|x| x.to_string()))\n            .bind(instrument.max_notional().map(|x| x.to_string()))\n            .bind(instrument.min_notional().map(|x| x.to_string()))\n            .bind(instrument.max_price().map(|x| x.to_string()))\n            .bind(instrument.min_price().map(|x| x.to_string()))\n            .bind(instrument.ts_init().to_string())\n            .bind(instrument.ts_event().to_string())\n            .execute(pool)\n            .await\n            .map(|_| ())\n            .map_err(|e| anyhow::anyhow!(\"Failed to insert item {} into instrument table: {:?}\", instrument.id(), e))\n    }\n\n    /// Loads a single `InstrumentAny` entry by `instrument_id` via the provided `pool`.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the SELECT operation fails.\n    pub async fn load_instrument(\n        pool: &PgPool,\n        instrument_id: &InstrumentId,\n    ) -> anyhow::Result<Option<InstrumentAny>> {\n        sqlx::query_as::<_, InstrumentAnyRow>(\"SELECT * FROM instrument WHERE id = $1\")\n            .bind(instrument_id.to_string())\n            .fetch_optional(pool)\n            .await\n            .map(|instrument| instrument.map(|row| row.0))\n            .map_err(|e| {\n                anyhow::anyhow!(\"Failed to load instrument with id {instrument_id},error is: {e}\")","sourceCodeStart":189,"sourceCodeEnd":225,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/infrastructure/src/sql/queries.rs#L189-L225","documentation":"`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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nDatabaseQueries::add_instrument(&pool, \"currency\", &instrument).await?;\n// after\nif let Err(e) = DatabaseQueries::add_instrument(&pool, \"currency\", &instrument).await {\n    tracing::error!(\"instrument {} upsert failed: {e:?}\", instrument.id());\n    return Err(e);\n}","handlingStrategy":"try-catch","validationCode":"let ready: bool = sqlx::query_scalar(\n    \"SELECT EXISTS (SELECT 1 FROM information_schema.tables WHERE table_name = 'instrument') \\\n     AND EXISTS (SELECT 1 FROM pg_type WHERE typname = 'asset_class')\",\n).fetch_one(pool).await?;\nif !ready {\n    return Err(anyhow::anyhow!(\"instrument schema missing — run migrations\"));\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = DatabaseQueries::add_instrument(&pool, kind, &instrument).await {\n    tracing::error!(\"instrument {} upsert failed: {e:?}\", instrument.id());\n    // inspect e for the failing column: null violation / numeric overflow / enum cast\n    return Err(anyhow::anyhow!(\"persisting {}: {e}\", instrument.id()));\n}","preventionTips":["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."],"tags":["postgres","sqlx","database","insert","instrument","upsert"],"backgroundTag":"database-write-failed","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}