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
- Locate the corrupt row by id (included in the message) and inspect its `sealed_transaction`, `raw_transaction`, and `payload_expected` values.
- 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.
- If the row should not have a payload at all, set `payload_expected=false` so it is excluded from rewrap batches.
- 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
- Enforce a DB CHECK/NOT NULL constraint pattern: rows with payload_expected=true must have sealed_transaction (via trigger or application invariant).
- Backfill/restores must seal envelopes under the active key before committing payload_expected rows.
- Run the NULL-envelope pre-check above before every rewrap window.
- Watch for crashed writers: alert on rows that have payload_expected but NULL envelope older than a threshold.
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
- Execution payload rewrap left {remaining} row(s)
- Execution payload {} contains plaintext during rewrap
- 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
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/1020b8d105f81127.
Report an issue: GitHub.