{"record":{"id":"1d3ec55b385f117b","repo":"nautechsystems/nautilus_trader","slug":"execution-transaction-hash-transaction-hash-was","errorCode":null,"errorMessage":"Execution transaction hash {transaction_hash} was not found for intent {intent_id}","messagePattern":"Execution transaction hash (.+?) was not found for intent (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":3662,"sourceCode":"                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}\"))?;\n","sourceCodeStart":3644,"sourceCodeEnd":3680,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/2114cf6f761429e0adb5ca9596fcd7b895b16011/crates/adapters/blockchain/src/cache/database.rs#L3644-L3680","documentation":"Guard inside record_execution_status (database.rs:3662-3665): the UPDATE ... WHERE intent_id = $1 AND transaction_hash = $2 affected zero rows. The WHERE clause has no status or current filter, so even a retired/replaced hash row would match; this fires only when the (intent_id, transaction_hash) pair does not exist in execution_transaction_hash at all. The whole transaction then rolls back, leaving the intent status untouched.","triggerScenarios":"Calling record_execution_status with a hash that was never persisted under that intent (a receipt observed for a broadcast hash recorded against a different intent_id), an intent_id belonging to another chain/instance, or a hash string that differs byte-for-byte from the stored value (missing 0x prefix, different casing, wrong length).","commonSituations":"A replacement transaction consumed the nonce but its hash was attached under another intent record; intent_id cached in a long-lived process across a database rebuild; hashes copied from logs or RPC responses with non-normalized casing; partial outage where intent rows survived but hash rows were pruned.","solutions":["Confirm the pair exists: call get_execution_transaction_hashes(intent_id) or run SELECT id, status FROM execution_transaction_hash WHERE intent_id = $1 AND transaction_hash = $2","If the hash is absent, persist it first through the normal signing/replacement recording path before replaying the receipt observation","Normalize the hash (0x-prefixed lowercase hex) on both the write and read paths and compare byte-for-byte with the stored value","If intent_id came from a restarted or legacy process, re-resolve it via get_active_execution_intent instead of caching it across restarts"],"exampleFix":"// before: assume the pair exists, discover the mismatch at UPDATE time\nlet _ = db.record_execution_status(intent_id, &hash, status, block, block_hash, ok, gas, price).await?;\n\n// after: validate the (intent_id, hash) pair first\nlet hashes = db.get_execution_transaction_hashes(intent_id).await?;\nlet normalized = hash.to_lowercase();\nif !hashes.iter().any(|r| r.transaction_hash == normalized) {\n    anyhow::bail!(\"hash {normalized} not persisted for intent {intent_id}; record it before applying a receipt\");\n}\nlet _ = db.record_execution_status(intent_id, &normalized, status, block, block_hash, ok, gas, price).await?;","handlingStrategy":"validation","validationCode":"let hashes = db.get_execution_transaction_hashes(intent_id).await?;\nlet normalized = hash.to_lowercase();\nanyhow::ensure!(\n    hashes.iter().any(|r| r.transaction_hash == normalized),\n    \"hash {normalized} not persisted for intent {intent_id}; record it before applying a receipt\"\n);","typeGuard":null,"tryCatchPattern":"match db.record_execution_status(...).await {\n    Ok(()) => Ok(()),\n    Err(e) if e.to_string().contains(\"was not found for intent\") => {\n        // data mismatch: reconcile hash/intent pairing, never retry blindly\n        log_and_alert(e)\n    }\n    Err(e) => Err(e),\n}","preventionTips":["Normalize transaction hashes (0x-prefixed lowercase hex) at every ingestion boundary","Never cache intent_id across process restarts; re-resolve via get_active_execution_intent","Ensure a hash is always persisted (signed/replacement path) before receipt observations reference it","Add a foreign-key-style invariant test: every (intent_id, hash) passed to record_execution_status exists after the preceding add/record calls"],"tags":["rust","sqlx","postgres","blockchain","not-found","data-integrity"],"backgroundTag":"database-row-not-found","analyzedSha":"2114cf6f761429e0adb5ca9596fcd7b895b16011","analyzedAt":"2026-08-21T11:28:30.864Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}