{"record":{"id":"297bb2a8387aff0c","repo":"nautechsystems/nautilus_trader","slug":"replacement-transaction-transaction-hash-is-not","errorCode":null,"errorMessage":"Replacement transaction {transaction_hash} is not authenticated","messagePattern":"Replacement transaction (.+?) is not authenticated","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":6445,"sourceCode":"                    \"\n                    SELECT id, payload_expected, current\n                    FROM execution_transaction_hash\n                    WHERE intent_id = $1 AND chain_id = $2 AND transaction_hash = $3\n                    FOR UPDATE\n                    \",\n                )\n                .bind(scan.intent_id)\n                .bind(chain_id)\n                .bind(transaction_hash)\n                .fetch_optional(&mut *transaction)\n                .await\n                .context(\"failed to lock authenticated replacement payload\")?\n                .ok_or_else(|| {\n                    anyhow::anyhow!(\n                        \"Replacement transaction {transaction_hash} has no retained payload\"\n                    )\n                })?;\n            anyhow::ensure!(\n                payload_expected,\n                \"Replacement transaction {transaction_hash} is not authenticated\"\n            );\n\n            if !already_current {\n                sqlx::query(\n                    \"\n                    UPDATE execution_transaction_hash\n                    SET current = FALSE, status = 'replaced', updated_at = NOW()\n                    WHERE intent_id = $1 AND current\n                    \",\n                )\n                .bind(scan.intent_id)\n                .execute(&mut *transaction)\n                .await\n                .context(\"failed to retire the prior transaction hash\")?;\n                sqlx::query(\n                    \"","sourceCodeStart":6427,"sourceCodeEnd":6463,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L6427-L6463","documentation":"After locking the `execution_transaction_hash` row, the code checks its `payload_expected` flag. If false, the row exists but its payload is not expected/authenticated (e.g. it was recorded without an authenticated payload or was previously retired), so treating this transaction as a verified replacement is refused.","triggerScenarios":"Attaching `matched_transaction_hash` where the stored row has `payload_expected = FALSE` — i.e. the hash was recorded but never backed by an authenticated payload, or its expected-payload flag was cleared.","commonSituations":"The payload authentication step failed or was skipped earlier in the pipeline; the row was written by a legacy/unauthenticated path; flags were mutated by a concurrent transition between retention and the scan record.","solutions":["Re-run the payload authentication step for the transaction so `payload_expected` becomes TRUE before recording the scan.","Only mark replacements whose payloads passed authentication; filter out unauthenticated hashes when building the scan.","Recreate the `execution_transaction_hash` row through the authenticated retention path if the flag was cleared incorrectly."],"exampleFix":"// before: accepting any stored hash\nlet scan = build_scan(stored_hashes);\n// after: only authenticated ones\nlet scan = build_scan(stored_hashes.into_iter().filter(|h| h.payload_expected));","handlingStrategy":"validation","validationCode":"let (payload_expected, current) = sqlx::query_as::<_, (bool, bool)>(\"SELECT payload_expected, current FROM execution_transaction_hash WHERE intent_id=$1 AND chain_id=$2 AND transaction_hash=$3\").bind(intent_id).bind(chain_id).bind(tx_hash).fetch_one(&pool).await?;\nif !payload_expected { return Err(anyhow!(\"tx {tx_hash} lacks an authenticated payload\")); }","typeGuard":"fn payload_is_authenticated(row: &(i64, bool, bool)) -> bool { row.1 }","tryCatchPattern":null,"preventionTips":["Run payload authentication before any scan that may match the transaction as a replacement.","Filter candidate replacement hashes on `payload_expected = TRUE` when building scans.","Re-authenticate rows whose payload flag was cleared before reusing them as replacements."],"tags":["database","authentication","consistency"],"backgroundTag":"invalid-state-transition","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"}