{"record":{"id":"5c01e5da476f1676","repo":"nautechsystems/nautilus_trader","slug":"plaintext-signed-transaction-persistence-is-disabl","errorCode":null,"errorMessage":"Plaintext signed transaction persistence is disabled after payload activation","messagePattern":"Plaintext signed transaction persistence is disabled after payload activation","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":6647,"sourceCode":"            let state = execution_payload_state_from_row(&state_row)?;\n            anyhow::ensure!(\n                state.protocol_version == EXECUTION_PAYLOAD_PROTOCOL_VERSION\n                    && state.operation == \"ready\",\n                \"Execution payload storage is not ready for protected persistence\"\n            );\n            anyhow::ensure!(\n                envelope_key_id(envelope)?.as_slice() == state.active_key_id.as_slice(),\n                \"Signed transaction envelope does not use the database active key\"\n            );\n        } else {\n            let marker = sqlx::query_scalar::<_, bool>(\n                \"SELECT EXISTS (SELECT 1 FROM execution_schema_version WHERE component = $1)\",\n            )\n            .bind(EXECUTION_PAYLOAD_COMPONENT)\n            .fetch_one(&mut *transaction)\n            .await\n            .context(\"failed to inspect execution payload marker\")?;\n            anyhow::ensure!(\n                !marker,\n                \"Plaintext signed transaction persistence is disabled after payload activation\"\n            );\n        }\n        let current_status = sqlx::query_scalar::<_, String>(\n            \"SELECT status FROM execution_intent WHERE id = $1 FOR UPDATE\",\n        )\n        .bind(intent_id)\n        .fetch_optional(&mut *transaction)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to lock execution intent {intent_id}: {e}\"))?\n        .ok_or_else(|| anyhow::anyhow!(\"Execution intent {intent_id} was not found\"))?;\n        anyhow::ensure!(\n            current_status == TransactionStatus::Prepared.as_str()\n                || current_status == TransactionStatus::Signed.as_str(),\n            \"Execution intent {intent_id} is {current_status}, not prepared for signing\"\n        );\n","sourceCodeStart":6629,"sourceCodeEnd":6665,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L6629-L6665","documentation":"After execution payload protection has been activated (an execution_schema_version marker row exists for the component), the database no longer accepts plaintext (raw, unsealed) signed-transaction payloads. This guard prevents a caller from bypassing encryption and writing raw transaction bytes once protected storage is enabled.","triggerScenarios":"Calling add_execution_transaction_payload with raw_transaction=Some (sealed_transaction=None) on a database where the execution_schema_version marker for EXECUTION_PAYLOAD_COMPONENT already exists — i.e. after payload-activation/encryption was enabled.","commonSituations":"Running an older node version that still writes raw payloads against a database migrated to protected storage; a rollback of code after activation; a config flag turning off sealing while the DB marker remains enabled.","solutions":["Upgrade/restore the sealing path so the payload is passed as sealed_transaction instead of raw_transaction.","If plaintext mode is genuinely required, revert the payload activation (remove the execution_schema_version marker) via the supported migration procedure — only in a maintenance window.","Ensure all writer instances run the same code version with payload protection enabled.","Check deployment configuration so the sealing flag matches the database's activated state."],"exampleFix":"// before\nadd_execution_transaction_payload(intent, chain, hash, Some(raw_bytes), None).await?;\n// after\nlet sealed = seal(payload, active_key)?;\nadd_execution_transaction_payload(intent, chain, hash, None, Some(sealed)).await?;","handlingStrategy":"validation","validationCode":"let activated: bool = sqlx::query_scalar(\"SELECT EXISTS (SELECT 1 FROM execution_schema_version WHERE component=$1)\").bind(component).fetch_one(&pool).await?;\nanyhow::ensure!(!(activated && sealed_transaction.is_none()), \"payload protection active: must pass sealed_transaction\");","typeGuard":null,"tryCatchPattern":"match result {\n    Err(e) if e.to_string().contains(\"Plaintext signed transaction persistence is disabled\") => {\n        error!(\"writer lacks payload sealing; upgrade node or enable sealing config before retrying\");\n    }\n    r => r?,\n}","preventionTips":["Keep all writer nodes on the same version as the database's payload-activation state","Gate the raw-transaction code path behind a config check that queries the DB marker at startup","Test rollbacks: never deploy a pre-activation writer against an activated database","Seal by default; treat raw persistence as a legacy-only mode"],"tags":["database","encryption","config-mismatch","transactions"],"backgroundTag":"feature-not-enabled","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"}