{"record":{"id":"c978689eb4b344b3","repo":"nautechsystems/nautilus_trader","slug":"failed-to-update-execution-hash-transaction-hash","errorCode":null,"errorMessage":"Failed to update execution hash {transaction_hash}: {e}","messagePattern":"Failed to update execution hash (.+?): (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":3661,"sourceCode":"                block_hash = COALESCE($5, block_hash),\n                receipt_success = COALESCE($6, receipt_success),\n                gas_used = COALESCE($7, gas_used),\n                effective_gas_price = COALESCE($8, effective_gas_price),\n                updated_at = NOW()\n            WHERE intent_id = $1 AND transaction_hash = $2\n            \",\n        )\n        .bind(intent_id)\n        .bind(transaction_hash)\n        .bind(status.as_str())\n        .bind(block_number_db)\n        .bind(block_hash)\n        .bind(receipt_success)\n        .bind(gas_used_db)\n        .bind(effective_gas_price)\n        .execute(&mut *transaction)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to update execution hash {transaction_hash}: {e}\"))?;\n        anyhow::ensure!(\n            hash_result.rows_affected() == 1,\n            \"Execution transaction hash {transaction_hash} was not found for intent {intent_id}\"\n        );\n\n        sqlx::query(\n            \"\n            UPDATE execution_intent\n            SET status = $2, active = $3, updated_at = NOW()\n            WHERE id = $1\n            \",\n        )\n        .bind(intent_id)\n        .bind(status.as_str())\n        .bind(active)\n        .execute(&mut *transaction)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to update execution intent {intent_id}: {e}\"))?;","sourceCodeStart":3643,"sourceCodeEnd":3679,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/2114cf6f761429e0adb5ca9596fcd7b895b16011/crates/adapters/blockchain/src/cache/database.rs#L3643-L3679","documentation":"Wrapped sqlx error from the UPDATE execution_transaction_hash statement inside record_execution_status (crates/adapters/blockchain/src/cache/database.rs:3638-3661), which persists a receipt observation (status, block_number, block_hash, receipt_success, gas_used, effective_gas_price) for one (intent_id, transaction_hash) pair. The {e} suffix carries the underlying sqlx::Error; this message only identifies which statement failed. The statement runs inside a transaction that already holds a FOR UPDATE lock on the intent row, so the most common causes are infrastructure faults or schema drift, not row contention.","triggerScenarios":"Calling record_execution_status when Postgres rejects or never receives the UPDATE: connection dropped mid-transaction, statement_timeout firing while waiting on other row locks, a serialization/deadlock abort (40001/40P01), a CHECK/NOT NULL violation on a bound column (e.g., an unexpected status string), or a database whose execution_transaction_hash schema lacks one of the eight bound columns because migrations were not applied.","commonSituations":"Postgres restart or failover while the blockchain watcher is processing receipts; running the cache against a database created by an older adapter version whose schema predates gas_used/effective_gas_price receipt columns; a concurrent watcher holding the intent lock past statement_timeout; connecting through a pool left half-dead after a network blip.","solutions":["Downcast to the root cause: err.downcast_ref::<sqlx::Error>() and read as_database_error() code/message to classify connection vs constraint vs timeout","Verify the schema is current: run the project's migrations so execution_transaction_hash matches the eight bound columns","For timeout/deadlock SQLSTATEs (57014/40P01/40001) retry the whole call with backoff - the transaction rolls back atomically and the transition_key makes the flow idempotent","If the cause is PoolTimedOut/Io, check Postgres reachability and pool sizing (max_connections, acquire_timeout)","Fix the offending bind value if a CHECK/NOT NULL/type violation is reported for a specific column"],"exampleFix":"// before: single shot, any error aborts receipt processing\nlet _ = db.record_execution_status(intent_id, hash, status, block, block_hash, ok, gas, price).await?;\n\n// after: classify and retry transient failures (rollback makes the call idempotent)\nfor attempt in 1..=3u32 {\n    match db.record_execution_status(intent_id, hash, status, block, block_hash, ok, gas, price).await {\n        Ok(()) => break,\n        Err(e) if attempt < 3 && is_transient_db_error(&e) => {\n            tokio::time::sleep(std::time::Duration::from_millis(100u64 * 2u64.pow(attempt))).await;\n        }\n        Err(e) => return Err(e),\n    }\n}","handlingStrategy":"retry","validationCode":null,"typeGuard":"fn is_transient_db_error(err: &anyhow::Error) -> bool {\n    match err.downcast_ref::<sqlx::Error>() {\n        Some(sqlx::Error::PoolTimedOut | sqlx::Error::PoolClosed | sqlx::Error::Io(_)) => true,\n        Some(e) => e.as_database_error().and_then(|d| d.code()).map_or(false, |c| {\n            matches!(c.as_ref(), \"40001\" | \"40P01\" | \"55P03\" | \"57014\" | \"08000\" | \"08003\" | \"08006\")\n        }),\n        None => false,\n    }\n}","tryCatchPattern":"match db.record_execution_status(...).await {\n    Ok(()) => {}\n    Err(e) if is_transient_db_error(&e) => retry_with_backoff(e), // whole call is idempotent after rollback\n    Err(e) => return Err(e), // constraint/schema faults: fix data or migrations, do not retry\n}","preventionTips":["Run migrations before deploying a new adapter version so execution_transaction_hash always matches the bound columns","Keep begin-to-commit windows short to limit exposure to timeouts and failovers","Monitor sqlx pool acquire timeouts and database error codes; alert on anything outside transient classes","Log err.chain() (root_cause) instead of only the top-level message so classification is possible after the fact"],"tags":["rust","sqlx","postgres","blockchain","receipt","transaction"],"backgroundTag":"database-update-failed","analyzedSha":"2114cf6f761429e0adb5ca9596fcd7b895b16011","analyzedAt":"2026-08-21T11:28:30.864Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}