{"record":{"id":"a81106ec9a7a8ef5","repo":"nautechsystems/nautilus_trader","slug":"execution-transaction-transaction-hash-conflicts","errorCode":null,"errorMessage":"Execution transaction {transaction_hash} conflicts with its persisted record","messagePattern":"Execution transaction (.+?) conflicts with its persisted record","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":3027,"sourceCode":"            WHERE execution_transaction.wallet_address = EXCLUDED.wallet_address\n              AND execution_transaction.nonce = EXCLUDED.nonce\n              AND execution_transaction.purpose = EXCLUDED.purpose\n              AND execution_transaction.status = EXCLUDED.status\n              AND execution_transaction.client_order_id IS NOT DISTINCT FROM EXCLUDED.client_order_id\n        \",\n        )\n        .bind(chain_id as i32)\n        .bind(wallet_address)\n        .bind(nonce as i64)\n        .bind(transaction_hash)\n        .bind(purpose)\n        .bind(status)\n        .bind(client_order_id)\n        .execute(&self.pool)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to insert into execution_transaction table: {e}\"))?;\n\n        anyhow::ensure!(\n            result.rows_affected() == 1,\n            \"Execution transaction {transaction_hash} conflicts with its persisted record\"\n        );\n        Ok(())\n    }\n\n    /// Installs execution schema version 2 without changing existing transaction rows.\n    ///\n    /// The migration locks the legacy transaction table, refuses unresolved version 1 rows,\n    /// installs the versioned intent and hash-history tables, and fences older writers before\n    /// releasing the lock. This prevents a mixed-version process from bypassing the new signer\n    /// ownership constraints.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the database operation fails.\n    pub async fn ensure_execution_transaction_schema(&self) -> anyhow::Result<()> {\n        let mut transaction = self","sourceCodeStart":3009,"sourceCodeEnd":3045,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/2114cf6f761429e0adb5ca9596fcd7b895b16011/crates/adapters/blockchain/src/cache/database.rs#L3009-L3045","documentation":"The execution_transaction insert uses ON CONFLICT (chain_id, transaction_hash) DO UPDATE ... WHERE every existing column (wallet_address, nonce, purpose, status, client_order_id) equals the incoming values, making exact re-insertion idempotent. rows_affected() == 0 (enforced at crates/adapters/blockchain/src/cache/database.rs:3027) means a row for that (chain_id, transaction_hash) already exists with different metadata - hash reuse or record mismatch - which the signer refuses rather than overwrite.","triggerScenarios":"Re-recording an existing transaction hash with any changed field: a different client_order_id or purpose for the same hash, a status transition submitted as a re-insert instead of an update, stale queued records replayed after a wallet/nonce change, or a genuine hash collision across wallets.","commonSituations":"An upstream bug assigning one tx hash to two operations; restoring from backup and replaying recorded transactions with updated statuses; multiple signer processes sharing the database with mismatched wallet configurations; manual database edits.","solutions":["Query the persisted row: SELECT * FROM execution_transaction WHERE chain_id = $1 AND transaction_hash = $2; and diff each column against the incoming values to find the mismatched field.","If the status legitimately advanced, apply the status change through the update path rather than re-inserting new metadata.","Ensure one writer path per wallet and never reuse a transaction hash across orders or purposes.","If the row is provably wrong, repair it deliberately with an audited migration/fixup instead of forcing the insert."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"-- Before recording, check the persisted row for this hash\nSELECT wallet_address, nonce, purpose, status, client_order_id\nFROM execution_transaction\nWHERE chain_id = $1 AND transaction_hash = $2;\n-- If a row exists, every column must match the values you are about to record","typeGuard":null,"tryCatchPattern":"if let Err(e) = db.add_execution_transaction(...).await {\n    if e.to_string().contains(\"conflicts with its persisted record\") {\n        // data integrity violation: halt, investigate the divergent row, never force-overwrite\n        log::error!(\"tx hash reuse or metadata mismatch detected: {e}\");\n        return Err(e);\n    }\n    return Err(e);\n}","preventionTips":["Never reuse a transaction hash across orders, purposes, or wallets.","Apply status changes through updates, not by re-inserting new metadata for the same hash.","Keep one writer path per wallet and audit any manual edits to execution_transaction.","Alert on this error: it indicates record divergence that could hide double execution."],"tags":["blockchain","transaction-hash","data-integrity","persistence"],"backgroundTag":"transaction-hash-conflict","analyzedSha":"2114cf6f761429e0adb5ca9596fcd7b895b16011","analyzedAt":"2026-08-21T11:28:30.864Z","schemaVersion":2},"datasetVersion":"2026-08-22T14:17:55.899Z"}