nautechsystems/nautilus_trader · error · anyhow::Error
Protected execution transaction {} contains plaintext
Error message
Protected execution transaction {} contains plaintext What it means
When payload-protection keys and a deployment id are available, the loader treats execution transactions as protected: rows must store only sealed envelopes, never plaintext signed bytes. This ensure! fires when a row's raw_transaction column is non-NULL even though protection is active, aborting the load to avoid exposing plaintext signing material.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:5225
for hash in &rows {
cursor = hash.id;
plaintext_rows += u64::from(hash.raw_transaction.is_some());
if !hash.payload_expected {
replacement_rows += 1;
anyhow::ensure!(
hash.raw_transaction.is_none() && hash.sealed_transaction.is_none(),
"Replacement execution transaction {} retains signed bytes",
hash.id
);
continue;
}
original_rows += 1;
let intent = load_execution_intent(&mut transaction, hash.intent_id).await?;
let raw_transaction = if let (Some(keys), Some(deployment_id)) =
(keys, deployment_id.as_deref())
{
anyhow::ensure!(
hash.raw_transaction.is_none(),
"Protected execution transaction {} contains plaintext",
hash.id
);
let envelope = hash.sealed_transaction.as_deref().ok_or_else(|| {
anyhow::anyhow!(
"Protected execution transaction {} has no envelope",
hash.id
)
})?;
let key_id = envelope_key_id(envelope)?;
anyhow::ensure!(
keys.contains_key(&key_id),
"Execution transaction {} requires an unavailable payload key",
hash.id
);
key_ids.insert(alloy::hex::encode(key_id));
let context = payload_context(&intent, hash, deployment_id)?;View on GitHub (pinned to 18893faf8b)
Solutions
- Run rewrap_execution_payload_storage with the correct PayloadKeySet to seal the remaining plaintext rows into envelopes.
- Verify the deployment_id supplied to the load matches the deployment_id recorded in execution_payload_state.
- For rows that should remain legacy (no protection), ensure keys/deployment_id are not passed so the legacy branch is taken instead.
- Check that payload protection setup (begin_execution_payload_rewrap) completed fully before loading.
Example fix
// Load before rewrap (protection active, row still plaintext) -> error load_execution_transactions(&pool, Some(&keys), Some(deployment_id)).await?; // after: complete rewrap first rewrap.rewrap_execution_payload_storage(&keys, 500).await?; load_execution_transactions(&pool, Some(&keys), Some(deployment_id)).await?;
Defensive patterns
Strategy: validation
Validate before calling
-- Rows still plaintext while protection is active SELECT id FROM execution_transactions WHERE raw_transaction IS NOT NULL AND (SELECT deployment_id FROM execution_payload_state WHERE component='signed_transactions') IS NOT NULL;
Try / catch
match load_result {
Err(e) if e.to_string().contains("contains plaintext") => {
run_payload_rewrap(&keys).await?;
retry_load().await
}
other => other,
} Prevention
- Always run the rewrap to completion immediately after enabling payload protection.
- Gate the loader on protection being active: refuse legacy loads when execution_payload_state exists.
- Monitor for rows written by nodes running pre-protection versions.
When it happens
Trigger: Calling the execution-transaction load path with keys and deployment_id supplied while the scanned row still has a non-NULL raw_transaction (e.g. a row written before protection was enabled and never rewrapped).
Common situations: Protection was recently enabled but the rewrap of legacy plaintext rows did not complete; rows inserted by an older node version; keys configured for the wrong deployment so rewrap skipped them.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Execution payload storage is in {operation} maintenance; com
- Execution payload protection is active, but no payload key i
- Execution payload storage is in {operation} maintenance, not
- Execution payload storage is in {operation} maintenance, not
- Protected execution transaction {} has no envelope
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/f2aaeaf6c33c94c9.
Report an issue: GitHub.