{"record":{"id":"5f61ebba791ccb23","repo":"nautechsystems/nautilus_trader","slug":"execution-payload-changed-during-seal-round-tri","errorCode":null,"errorMessage":"Execution payload {} changed during seal round trip","messagePattern":"Execution payload (.+?) changed during seal round trip","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":4971,"sourceCode":"                hash.id\n            );\n            let raw_transaction = hash\n                .raw_transaction\n                .as_deref()\n                .expect(\"migration query requires plaintext\");\n            let intent = load_execution_intent(&mut transaction, hash.intent_id).await?;\n            let context = authenticate_retained_payload(\n                raw_transaction,\n                &intent,\n                &hash,\n                keys.deployment_id(),\n            )\n            .with_context(|| format!(\"failed to authenticate execution payload {}\", hash.id))?;\n            reserve_execution_payload_seal(&mut transaction, keys.active_key_id()).await?;\n            let envelope = keys.seal(raw_transaction, &context)?;\n            let unsealed = keys.unseal(&envelope, &context)?;\n            authenticate_retained_payload(&unsealed, &intent, &hash, keys.deployment_id())?;\n            anyhow::ensure!(\n                unsealed == raw_transaction,\n                \"Execution payload {} changed during seal round trip\",\n                hash.id\n            );\n            let result = sqlx::query(\n                \"UPDATE execution_transaction_hash \\\n                 SET sealed_transaction = $2, raw_transaction = NULL, updated_at = NOW() \\\n                 WHERE id = $1 AND raw_transaction = $3 AND sealed_transaction IS NULL\",\n            )\n            .bind(hash.id)\n            .bind(&envelope)\n            .bind(raw_transaction)\n            .execute(&mut *transaction)\n            .await\n            .context(\"failed to promote execution payload\")?;\n            anyhow::ensure!(\n                result.rows_affected() == 1,\n                \"Execution payload {} changed during migration\",","sourceCodeStart":4953,"sourceCodeEnd":4989,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L4953-L4989","documentation":"Before persisting a sealed envelope, the driver seals the plaintext with the active key, immediately unseals it, authenticates it, and asserts the round trip reproduced the original bytes. A mismatch means the ciphertext does not faithfully encode the payload — a cryptographic/keying bug or memory corruption — so the update is aborted rather than storing a lossy envelope.","triggerScenarios":"During migrate_execution_payload_batch, keys.seal(...) followed by keys.unseal(...) returns bytes != raw_transaction for a given hash id — e.g. wrong key version in the key set, a broken codec, or nondeterministic context mismatches.","commonSituations":"Rotated/deployed key not matching the one used for seal; deployment_id mismatch between keys and stored intent; library/protocol version skew between writer and migrator; corrupted raw_transaction bytes.","solutions":["Verify the PayloadKeySet deployment_id and active key match the deployment that stored the payloads","Re-run the batch with a consistent key set — if it recurs, treat the affected rows as corrupt and restore from backup","Check for version skew between the sealing library/protocol version and the migrator binary","Report/preserve the failing hash id and raw bytes; do not hand-edit sealed payloads"],"exampleFix":"// before: migrating with possibly stale keys\nlet keys = load_key_set_from_env()?;\n// after: verify deployment id matches stored state before sealing\nlet keys = load_key_set_from_env()?;\nassert_eq!(keys.deployment_id(), expected_deployment_id, \"key set deployment mismatch\");","handlingStrategy":"try-catch","validationCode":"// verify key set matches the deployment before sealing\nif keys.deployment_id() != expected_deployment_id {\n    anyhow::bail!(\"payload key set deployment mismatch\");\n}","typeGuard":"fn keys_match_deployment(keys: &PayloadKeySet, expected: &DeploymentId) -> bool {\n    keys.deployment_id() == expected\n}","tryCatchPattern":"match db.migrate_execution_payload_batch(&keys, 500).await {\n    Ok(done) => {}\n    Err(e) if e.to_string().contains(\"changed during seal round trip\") => {\n        // halt migration, preserve the failing hash id, restore keys/data before retry\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Pin protocol/key versions across all nodes and migration tooling","Verify key set deployment_id and active_key_id against stored state before sealing","Never edit sealed payloads or raw bytes directly","Restore affected rows from backup if round-trip failures repeat"],"tags":["crypto","round-trip","data-integrity"],"backgroundTag":"checksum-mismatch","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"}