nautechsystems/nautilus_trader · error · anyhow::Error

Execution payload {} has no envelope during rewrap

Error message

Execution payload {} has no envelope during rewrap

What it means

While rewrapping, each row selected for rewrap must have a sealed envelope in `sealed_transaction` to unseal and re-seal under the new key. This error fires when a row in the batch has `payload_expected=true` but `sealed_transaction IS NULL`, so there is no envelope to rewrap. The library treats this as unrecoverable data corruption rather than silently skipping the payload.

Source

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

                "Execution payload rewrap left {remaining} row(s)"
            );
            sqlx::query(
                "UPDATE execution_payload_state SET operation = 'ready', updated_at = NOW() \
                 WHERE component = 'signed_transactions' AND operation = 'rewrap'",
            )
            .execute(&mut *transaction)
            .await
            .context("failed to mark execution payload rewrap complete")?;
            transaction
                .commit()
                .await
                .context("failed to commit execution payload rewrap completion")?;
            return Ok(true);
        }

        for hash in rows {
            let envelope = hash.sealed_transaction.as_deref().ok_or_else(|| {
                anyhow::anyhow!(
                    "Execution payload {} has no envelope during rewrap",
                    hash.id
                )
            })?;
            anyhow::ensure!(
                hash.raw_transaction.is_none(),
                "Execution payload {} contains plaintext during rewrap",
                hash.id
            );
            let intent = load_execution_intent(&mut transaction, hash.intent_id).await?;
            let context = payload_context(&intent, &hash, keys.deployment_id())?;
            let raw_transaction = keys.unseal(envelope, &context)?;
            authenticate_retained_payload(&raw_transaction, &intent, &hash, keys.deployment_id())?;
            reserve_execution_payload_seal(&mut transaction, keys.active_key_id()).await?;
            let rewrapped = keys.seal(&raw_transaction, &context)?;
            let verified = keys.unseal(&rewrapped, &context)?;
            authenticate_retained_payload(&verified, &intent, &hash, keys.deployment_id())?;
            anyhow::ensure!(

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Locate the corrupt row by id (included in the message) and inspect its `sealed_transaction`, `raw_transaction`, and `payload_expected` values.
  2. Restore the envelope from a backup or source of truth, or re-create the payload: fetch the plaintext transaction and seal it under the active key before re-running the rewrap.
  3. If the row should not have a payload at all, set `payload_expected=false` so it is excluded from rewrap batches.
  4. Fix the writer path that produced payload_expected rows without envelopes, then retry the rewrap.
Defensive patterns

Strategy: validation

Validate before calling

let bad: Vec<i64> = sqlx::query_scalar("SELECT id FROM execution_transaction_hash WHERE payload_expected AND sealed_transaction IS NULL")
    .fetch_all(&pool).await?;
if !bad.is_empty() {
    // remediate (re-seal or set payload_expected=false) before starting a rewrap
}

Try / catch

match rewrap_result {
    Err(e) if e.to_string().contains("has no envelope during rewrap") => {
        // parse row id from message, restore/re-seal or clear payload_expected, then retry
    },
    other => other?,
}

Prevention

When it happens

Trigger: A row matched the batch query but has a NULL `sealed_transaction` — possible when the row is mutated between the batch SELECT and processing, or when data was written by a path that marked `payload_expected` without storing a sealed envelope; also when the verification SELECT (with its OR `sealed_transaction IS NULL` clause) and the batch SELECT disagree on NULL-envelope rows due to concurrent modification.

Common situations: A crashed writer inserted rows with `payload_expected=true` but never populated `sealed_transaction`; a restore/ETL backfill left envelopes NULL; concurrent transactions cleared `sealed_transaction` while the rewrap loop held the batch rows FOR UPDATE but the row was updated in a window not covered by the lock.

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