{"record":{"id":"ec3c14cdaee56e64","repo":"nautechsystems/nautilus_trader","slug":"failed-to-insert-into-dex-table-e","errorCode":null,"errorMessage":"Failed to insert into dex table: {e}","messagePattern":"Failed to insert into dex table: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":789,"sourceCode":"            \"\n            INSERT INTO dex (\n                chain_id, name, factory_address, creation_block\n            ) VALUES ($1, $2, $3, $4)\n            ON CONFLICT (chain_id, name)\n            DO UPDATE\n            SET\n                factory_address = $3,\n                creation_block = $4\n        \",\n        )\n        .bind(dex.chain.chain_id as i32)\n        .bind(dex.name.to_string())\n        .bind(dex.factory.to_string())\n        .bind(dex.factory_creation_block as i64)\n        .execute(&self.pool)\n        .await\n        .map(|_| ())\n        .map_err(|e| anyhow::anyhow!(\"Failed to insert into dex table: {e}\"))\n    }\n\n    /// Adds or updates a liquidity pool/pair record in the database.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the database operation fails.\n    pub async fn add_pool(&self, pool: &Pool) -> anyhow::Result<()> {\n        sqlx::query(\n            \"\n            INSERT INTO pool (\n                chain_id, address, pool_identifier, dex_name, creation_block,\n                token0_chain, token0_address,\n                token1_chain, token1_address,\n                fee, tick_spacing, initial_tick, initial_sqrt_price_x96, hook_address\n            ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14)\n            ON CONFLICT (chain_id, dex_name, pool_identifier)\n            DO UPDATE","sourceCodeStart":771,"sourceCodeEnd":807,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L771-L807","documentation":"Database write error in the blockchain cache's dex insert: the SQLx upsert of a DEX row (chain_id, name, factory_address, creation_block) into PostgreSQL failed; the underlying driver error is embedded in the message.","triggerScenarios":"Calling the DEX insert when `dex.name`, `dex.factory`, or `factory_creation_block` violate column constraints (NULL in NOT NULL column, factory address not valid TEXT/too long), a cast failure binding address types, or Postgres connectivity loss during execute.","commonSituations":"Factory address produced from mis-decoded log data (invalid hex/empty string); fresh DB without the dex table; concurrent workers upserting the same factory with conflicting ON CONFLICT targets; DB role lacking INSERT privilege.","solutions":["Read the wrapped `{e}` to identify the failing column/constraint","Validate the DEX record before insert: non-empty valid address strings for name/factory, factory_creation_block within i64 range","Confirm migrations created the `dex` table and the DB role has INSERT/UPDATE rights","Check the ON CONFLICT target matches the table's actual unique index if upserts fail with 'no unique constraint' errors"],"exampleFix":"// before\nif dex.name.is_empty() { /* still inserted */ }\ndb.insert_dex(&dex).await?;\n// after\nanyhow::ensure!(!dex.name.is_empty() && is_valid_address(&dex.factory), \"invalid dex record\");\ndb.insert_dex(&dex).await?;","handlingStrategy":"validation","validationCode":"anyhow::ensure!(!dex.name.is_empty(), \"dex name empty\");\nanyhow::ensure!(is_valid_address(&dex.factory), \"invalid factory address\");\nanyhow::ensure!(dex.factory_creation_block <= i64::MAX as u64, \"creation block out of range\");","typeGuard":"fn dex_valid(dex: &Dex) -> bool {\n    !dex.name.is_empty()\n        && dex.factory.len() == 42 && dex.factory.starts_with(\"0x\")\n        && dex.factory_creation_block <= i64::MAX as u64\n}","tryCatchPattern":"if let Err(e) = db.insert_dex(&dex).await {\n    if e.to_string().contains(\"duplicate key\") { tracing::debug!(\"dex already present\"); }\n    else { return Err(e.context(format!(\"inserting dex {}\", dex.name))); }\n}","preventionTips":["Register the DEX before inserting pools that reference it","Validate address format/length from decoded logs before persistence","Keep the ON CONFLICT target in sync with the table's unique index"],"tags":["database","postgres","sqlx","insert"],"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-14T00:17:10.932Z"}