{"record":{"id":"663bbaed9c382cbd","repo":"nautechsystems/nautilus_trader","slug":"replacement-transaction-transaction-hash-has-no","errorCode":null,"errorMessage":"Replacement transaction {transaction_hash} has no retained payload","messagePattern":"Replacement transaction (.+?) has no retained payload","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":6441,"sourceCode":"                \"Intent cannot attach a verified replacement from status {current_status}\"\n            );\n            let (hash_id, payload_expected, already_current) =\n                sqlx::query_as::<_, (i64, bool, bool)>(\n                    \"\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)","sourceCodeStart":6423,"sourceCodeEnd":6459,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L6423-L6459","documentation":"A replacement transaction hash can only be attached if a row exists in `execution_transaction_hash` for (intent_id, chain_id, transaction_hash). This row is created when the transaction payload was first retained/authenticated. If the locked lookup returns no row, the hash being claimed as a verified replacement was never retained by the system, so attachment is refused.","triggerScenarios":"Setting `scan.matched_transaction_hash` to a tx hash that was never persisted to `execution_transaction_hash` for this intent/chain — e.g. a hash observed off-chain (mempool, explorer) without going through the authenticated retention path, or a hash belonging to a different intent.","commonSituations":"Scanning an explorer API found the replacement but the internal retention step never ran or used a different intent id; a copy/paste or encoding difference (checksummed vs lowercase hex) makes the hash not match the stored key.","solutions":["Retain and authenticate the replacement transaction payload through the normal retention API first, then re-run the scan record step.","Normalize the hash casing/encoding so it matches how it was stored (lowercase hex, same bytes).","Verify the hash belongs to this intent_id and chain_id, not another intent's replacement."],"exampleFix":"// before: hash straight from an explorer lookup\nlet scan = ExecutionReplacementScan { matched_transaction_hash: Some(explorer_tx_hash), .. };\n// after: retain first\nlet retained = db.retain_transaction_payload(chain_id, intent_id, explorer_tx_hash, payload).await?;\nlet scan = ExecutionReplacementScan { matched_transaction_hash: Some(retained.hash), .. };","handlingStrategy":"validation","validationCode":"let retained = sqlx::query_scalar::<_, i64>(\"SELECT id FROM execution_transaction_hash WHERE intent_id=$1 AND chain_id=$2 AND transaction_hash=$3\").bind(scan.intent_id).bind(chain_id).bind(tx_hash).fetch_optional(&pool).await?;\nif retained.is_none() { return Err(anyhow!(\"replacement tx {tx_hash} was never retained for this intent\")); }","typeGuard":"async fn hash_is_retained(pool: &PgPool, intent_id: i64, chain_id: i32, hash: &str) -> anyhow::Result<bool> {\n    Ok(sqlx::query_scalar::<_, i64>(\"SELECT id FROM execution_transaction_hash WHERE intent_id=$1 AND chain_id=$2 AND transaction_hash=$3\")\n        .bind(intent_id).bind(chain_id).bind(hash).fetch_optional(pool).await?.is_some())\n}","tryCatchPattern":null,"preventionTips":["Only use transaction hashes that went through the internal authenticated retention path.","Normalize hashes (lowercase hex) before storage and lookup to avoid key mismatches.","Confirm the hash belongs to the same intent_id/chain_id before attaching it."],"tags":["database","blockchain","entity-not-found"],"backgroundTag":"record-not-found","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"}