{"record":{"id":"54402029f37efd67","repo":"nautechsystems/nautilus_trader","slug":"retained-terminal-receipt-is-above-the-verified-fi","errorCode":null,"errorMessage":"Retained terminal receipt is above the verified finalized boundary","messagePattern":"Retained terminal receipt is above the verified finalized boundary","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":5505,"sourceCode":"                nonce < next_canonical_nonce,\n                \"Retained active nonce {nonce} is above canonical nonce {next_canonical_nonce}\"\n            );\n\n            let receipt_verification = required_verification(\n                self.verification\n                    .verify_receipt(&B256::from_str(&current.transaction_hash).with_context(\n                        || {\n                            format!(\n                                \"Retained transaction hash {} is invalid\",\n                                current.transaction_hash\n                            )\n                        },\n                    )?)\n                    .await,\n                \"migration receipt\",\n            )?;\n            let receipt = receipt_verification.value.clone();\n            anyhow::ensure!(\n                receipt.block_number <= finalized.number,\n                \"Retained terminal receipt is above the verified finalized boundary\"\n            );\n            let inclusion_verification = required_verification(\n                self.verification.verify_block(receipt.block_number).await,\n                \"migration inclusion header\",\n            )?;\n            anyhow::ensure!(\n                inclusion_verification.value.hash == receipt.block_hash\n                    && finalized_headers.iter().any(|header| {\n                        header.number == receipt.block_number\n                            && header.hash == receipt.block_hash.to_string()\n                    }),\n                \"Retained terminal receipt is not on the verified finalized ancestry\"\n            );\n            let tx_hash = B256::from_str(&current.transaction_hash)\n                .context(\"Retained transaction hash is invalid\")?;\n            let included = IncludedTransaction {","sourceCodeStart":5487,"sourceCodeEnd":5523,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L5487-L5523","documentation":"When migrating a retained terminal (finalized/reverted) intent, the client fetches its receipt and requires the receipt's block number to be at or below the currently verified `finalized` block. This error is thrown when the stored transaction receipt points to a block that the node no longer considers finalized — i.e. the receipt cannot be proven final under the current finalized header, so the terminal status cannot be safely migrated. It guards against trusting receipts from unfinalized or reorged-out blocks.","triggerScenarios":"Raised by `anyhow::ensure!(receipt.block_number <= finalized.number, ...)` when: the node's finalized head moved backwards or the migration runs against a different/forked chain than the one that produced the receipt; the node is behind and its `finalized` block is older than the receipt's block; or the persisted receipt references a block from an uncle/reorged fork.","commonSituations":"Switching RPC providers or networks (testnet vs fork) while retaining state; a chain reorg invalidating previously 'final' receipts (weak-finality chains); running migration immediately after node startup before finalized head catches up; replaying state from a snapshot ahead of the current node's finalized block.","solutions":["Wait for the node to sync so its finalized block number is >= the receipt's block number, then re-run migration.","Verify you are connected to the same chain/network the receipts were produced on; fix the RPC/chain config and retry.","Re-verify the intent's transaction on-chain (fetch a fresh receipt) and update the stored terminal record if the original receipt was from a reorged block.","If the receipt's block genuinely lost finality, revert the intent to a recoverable state so it can be re-prepared and re-signed."],"exampleFix":"// before (migrating against a lagging node)\nlet finalized = provider.latest_finalized().await?;  // block 100\n// receipt.block_number = 105 -> error\n\n// after (gate migration on finality catch-up)\nif finalized.number < receipt.block_number {\n    wait_for_finality(receipt.block_number).await?;\n}","handlingStrategy":"retry","validationCode":"async fn finality_caught_up(provider: &Provider, receipt_block: u64) -> Result<bool, Error> {\n    let finalized = provider.get_finalized_block().await?;\n    Ok(finalized.number >= receipt_block)\n}","typeGuard":"fn receipt_is_final(receipt_block: u64, finalized_number: u64) -> bool {\n    receipt_block <= finalized_number\n}","tryCatchPattern":"// retry until the node's finalized head passes the receipt block\nloop {\n    match run_migration().await {\n        Err(e) if e.to_string().contains(\"above the verified finalized boundary\") => {\n            tokio::time::sleep(Duration::from_secs(12)).await; // ~1 block\n            continue;\n        }\n        other => break other,\n    }\n}","preventionTips":["Only run migration after the node reports a healthy, current finalized head.","Use the same chain/RPC endpoint that produced the retained receipts.","On weak-finality chains, wait extra confirmations before persisting receipts as terminal.","Alert on finalized-head regressions, which indicate reorgs that can invalidate retained receipts."],"tags":["blockchain","finality","receipt-verification","state-migration"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}