nautechsystems/nautilus_trader · error · anyhow::Error

Legacy execution transaction {} has no plaintext

Error message

Legacy execution transaction {} has no plaintext

What it means

In the legacy load path, a row has neither a sealed envelope (expected there) nor a plaintext raw transaction, so there is nothing to return. The loader converts the missing raw_transaction into this anyhow error naming the row id.

Source

Thrown at crates/adapters/blockchain/src/cache/database.rs:5252

                        )
                    })?;
                    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)?;
                    keys.unseal(envelope, &context)?
                } else {
                    anyhow::ensure!(
                        hash.sealed_transaction.is_none(),
                        "Legacy execution transaction {} contains an envelope",
                        hash.id
                    );
                    hash.raw_transaction.clone().ok_or_else(|| {
                        anyhow::anyhow!("Legacy execution transaction {} has no plaintext", hash.id)
                    })?
                };
                authenticate_retained_payload(
                    &raw_transaction,
                    &intent,
                    hash,
                    deployment_id.as_deref().unwrap_or(""),
                )?;

                if let Some(policy) = policy
                    && retained_payload_requires_policy(&intent, hash, policy)?
                {
                    authenticate_payload(
                        &raw_transaction,
                        &intent,
                        hash,
                        policy,
                        deployment_id.as_deref().unwrap_or(""),

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Restore the row's payload from a backup or re-derive it from the execution intent source.
  2. If the row was migrated to sealed form, load with keys and deployment_id so the protected path is used.
  3. Inspect the row: if sealed_transaction exists, switch to protected loading instead of expecting plaintext.
  4. Check writer logs for a failed payload write when the row was created.

Example fix

// Row missing payload in legacy mode
{ id: "0x123", raw_transaction: null, sealed_transaction: null }
// after restore
{ id: "0x123", raw_transaction: "0x02f8...", sealed_transaction: null }
Defensive patterns

Strategy: validation

Validate before calling

-- Rows with no payload at all
SELECT id FROM execution_transactions
WHERE raw_transaction IS NULL AND sealed_transaction IS NULL;

Try / catch

let raw = match row.raw_transaction {
    Some(bytes) => bytes,
    None => return Err(anyhow!("row {} has no plaintext; restore or switch to protected load", row.id)),
};

Prevention

When it happens

Trigger: Loading execution transactions without keys/deployment_id while a row's raw_transaction column is NULL (and sealed_transaction is also NULL, otherwise 2224 fires first).

Common situations: Rows whose payload was cleared after reclassification but not restored; a partially completed sealing migration deleted plaintext without writing envelopes; loading a truncated/partial backup.

Understand the failure class

Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/6c774240e9160cc1. Report an issue: GitHub.