{"record":{"id":"9946be7b1d4af734","repo":"nautechsystems/nautilus_trader","slug":"execution-payload-contains-plaintext-during-rew","errorCode":null,"errorMessage":"Execution payload {} contains plaintext during rewrap","messagePattern":"Execution payload (.+?) contains plaintext during rewrap","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":5495,"sourceCode":"            )\n            .execute(&mut *transaction)\n            .await\n            .context(\"failed to mark execution payload rewrap complete\")?;\n            transaction\n                .commit()\n                .await\n                .context(\"failed to commit execution payload rewrap completion\")?;\n            return Ok(true);\n        }\n\n        for hash in rows {\n            let envelope = hash.sealed_transaction.as_deref().ok_or_else(|| {\n                anyhow::anyhow!(\n                    \"Execution payload {} has no envelope during rewrap\",\n                    hash.id\n                )\n            })?;\n            anyhow::ensure!(\n                hash.raw_transaction.is_none(),\n                \"Execution payload {} contains plaintext during rewrap\",\n                hash.id\n            );\n            let intent = load_execution_intent(&mut transaction, hash.intent_id).await?;\n            let context = payload_context(&intent, &hash, keys.deployment_id())?;\n            let raw_transaction = keys.unseal(envelope, &context)?;\n            authenticate_retained_payload(&raw_transaction, &intent, &hash, keys.deployment_id())?;\n            reserve_execution_payload_seal(&mut transaction, keys.active_key_id()).await?;\n            let rewrapped = keys.seal(&raw_transaction, &context)?;\n            let verified = keys.unseal(&rewrapped, &context)?;\n            authenticate_retained_payload(&verified, &intent, &hash, keys.deployment_id())?;\n            anyhow::ensure!(\n                verified == raw_transaction,\n                \"Execution payload {} changed during rewrap\",\n                hash.id\n            );\n            let result = sqlx::query(","sourceCodeStart":5477,"sourceCodeEnd":5513,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L5477-L5513","documentation":"During rewrap, a row must hold its payload exclusively in sealed form: `raw_transaction` (plaintext) must be NULL. This `anyhow::ensure!` fires when a row selected for rewrap still carries a plaintext `raw_transaction`, which would mean rewrapping the envelope could desynchronize the two copies or leak the plaintext the encryption scheme is meant to remove. The library refuses to rewrap such rows.","triggerScenarios":"A row in the rewrap batch has both `payload_expected=true` and a non-NULL `raw_transaction` — e.g. a writer stored the plaintext transaction after the rewrap began (post-lock race), a prior migration step that clears `raw_transaction` after sealing was interrupted, or manual data manipulation left plaintext in place.","commonSituations":"An older adapter version or fallback path that wrote plaintext `raw_transaction` while `sealed_transaction` was also populated; a partially completed earlier rewrap where the plaintext-clearing UPDATE never ran; manual imports/backfills that set `raw_transaction` directly; restoring rows from a pre-encryption-era backup.","solutions":["Find the offending row by id (from the message) and confirm both `raw_transaction` and `sealed_transaction` are populated.","Verify the sealed envelope decrypts to the same plaintext (`raw_transaction`), then clear `raw_transaction` (set it NULL) so the rewrap can proceed.","Identify and stop the code path writing plaintext into `raw_transaction` (old version, fallback writer, ETL) before re-running the rewrap.","If the plaintext row cannot be trusted, re-create the payload from the transaction source and seal it under the active key, then clear the plaintext column."],"exampleFix":"-- before: plaintext retained alongside sealed envelope\nSELECT id, raw_transaction, sealed_transaction FROM execution_transaction_hash WHERE id = <id>;\n-- after: verify envelope matches, then clear plaintext so rewrap can proceed\nUPDATE execution_transaction_hash SET raw_transaction = NULL, updated_at = NOW() WHERE id = <id>;","handlingStrategy":"validation","validationCode":"let plaintext_rows: Vec<i64> = sqlx::query_scalar(\"SELECT id FROM execution_transaction_hash WHERE payload_expected AND raw_transaction IS NOT NULL\")\n    .fetch_all(&pool).await?;\nif !plaintext_rows.is_empty() {\n    // verify sealed envelopes decrypt to the plaintext, then clear raw_transaction before rewrap\n}","typeGuard":null,"tryCatchPattern":"match rewrap_result {\n    Err(e) if e.to_string().contains(\"contains plaintext during rewrap\") => {\n        // parse row id, verify envelope vs plaintext, clear raw_transaction, retry rewrap\n    },\n    other => other?,\n}","preventionTips":["Deprecate/remove any code path that writes `raw_transaction` alongside sealed envelopes.","After a failed rewrap, check whether the plaintext-clearing step ran; re-run remediation before retrying.","Add a periodic audit query for payload_expected rows with non-NULL raw_transaction and alert immediately (plaintext retention risk).","Validate restored/pre-encryption-era rows and seal-or-strip plaintext before admitting them into the table."],"tags":["database","data-integrity","encryption","plaintext-leak","rust"],"backgroundTag":"internal-invariant-violation","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"}