nautechsystems/nautilus_trader · error

Protected execution transaction {} has no sealed payload

Error message

Protected execution transaction {} has no sealed payload

What it means

When a transaction row declares a protected (sealed) payload, the code requires `sealed_transaction` to hold the sealed envelope bytes. If the envelope is absent, unsealing is impossible and submission aborts. This is the counterpart of the plaintext check: protected rows must carry exactly a sealed payload.

Source

Thrown at crates/adapters/blockchain/src/execution/client.rs:3630

fn open_execution_payload(
    keys: &PayloadKeySet,
    policy: PayloadPolicy,
    intent: &ExecutionIntentRow,
    hash: &ExecutionTransactionHashRow,
    reason: &str,
) -> anyhow::Result<Vec<u8>> {
    anyhow::ensure!(
        hash.payload_expected,
        "Execution transaction {} has no signed payload",
        hash.transaction_hash
    );
    anyhow::ensure!(
        hash.raw_transaction.is_none(),
        "Protected execution transaction {} contains plaintext",
        hash.transaction_hash
    );
    let envelope = hash.sealed_transaction.as_deref().ok_or_else(|| {
        anyhow::anyhow!(
            "Protected execution transaction {} has no sealed payload",
            hash.transaction_hash
        )
    })?;
    let context = payload_context(intent, hash, keys.deployment_id())?;
    let raw_transaction = keys.unseal(envelope, &context)?;
    log::info!(
        "Unsealed execution payload for intent {} transaction {} during {reason}",
        intent.id,
        hash.transaction_hash
    );
    authenticate_retained_payload(&raw_transaction, intent, hash, keys.deployment_id())?;
    if retained_payload_requires_policy(intent, hash, policy)? {
        authenticate_payload(&raw_transaction, intent, hash, policy, keys.deployment_id())
            .with_context(|| {
                format!(
                    "execution intent {} transaction {} violates current execution policy",
                    intent.id, hash.transaction_hash

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Re-run the sealing/signing step to regenerate the envelope and persist it into sealed_transaction.
  2. Check the KMS/sealing service availability and credentials if sealing failed upstream.
  3. Restore the missing envelope from the blob store/backup or rebuild the row by replaying the pipeline.
  4. If the transaction should not be sealed, correct payload_expected/sealing policy rather than fabricating an envelope.

Example fix

// before: row recorded before sealing finished
store.record_hash(row)?; // sealed_transaction still None

// after
row.sealed_transaction = Some(sealing_service.seal(&signed_tx, &context)?);
store.record_hash(row)?;
Defensive patterns

Strategy: validation

Validate before calling

if hash.payload_expected && hash.raw_transaction.is_none() && hash.sealed_transaction.as_deref().map_or(true, |s| s.is_empty()) {
    anyhow::bail!("tx {} missing sealed envelope; re-seal before submission", hash.transaction_hash);
}

Type guard

fn has_sealed_payload(hash: &ExecutionTransactionHashRow) -> bool {
    hash.sealed_transaction.as_deref().map_or(false, |s| !s.is_empty())
}

Try / catch

match resolve_payload(keys, policy, intent, hash, reason) {
    Ok(bytes) => submit(bytes),
    Err(e) if e.to_string().contains("no sealed payload") => reseed_and_reseal(intent, hash),
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: Calling the payload-resolution function with a hash row where `payload_expected` is true, `raw_transaction` is None, but `sealed_transaction` is also None or empty — the sealed envelope was never persisted or was deleted.

Common situations: Crash between writing the hash row and persisting the sealed envelope; a cleanup/GC job that removed sealed blobs but not the rows; failed KMS/sealing-service call that was swallowed; restoring rows from a backup without the blob store.

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/fbaa88f6e6806f8f. Report an issue: GitHub.