nautechsystems/nautilus_trader · error · anyhow::Error

Execution payload storage is not rewrapping

Error message

Execution payload storage is not rewrapping

What it means

After locking the `execution_payload_state` row, `rewrap_execution_payload_batch` treats operation 'ready' as 'nothing to do' and otherwise requires the operation to be exactly 'rewrap'. This `anyhow::ensure!` fires when the stored operation is neither 'ready' nor 'rewrap', meaning the payload storage is in some other maintenance mode and cannot be safely batch-rewrapped.

Source

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

        lock_execution_payload_operation(&mut transaction).await?;
        let state_row = sqlx::query(
            "SELECT deployment_id, protocol_version, operation, active_key_id \
             FROM execution_payload_state WHERE component = 'signed_transactions' FOR UPDATE",
        )
        .fetch_optional(&mut *transaction)
        .await
        .context("failed to lock execution payload rewrap state")?
        .ok_or_else(|| anyhow::anyhow!("Execution payload rewrap state is missing"))?;
        let state = execution_payload_state_from_row(&state_row)?;
        validate_execution_payload_state(&state, keys)?;
        if state.operation == "ready" {
            transaction
                .commit()
                .await
                .context("failed to complete execution payload rewrap")?;
            return Ok(true);
        }
        anyhow::ensure!(
            state.operation == "rewrap",
            "Execution payload storage is not rewrapping"
        );
        let rows = sqlx::query_as::<_, ExecutionTransactionHashRow>(
            "
            SELECT
                id, intent_id, chain_id, transaction_hash, payload_expected,
                raw_transaction, sealed_transaction, status, block_number, block_hash,
                receipt_success, gas_used, effective_gas_price, current
            FROM execution_transaction_hash
            WHERE payload_expected
              AND substring(sealed_transaction FROM 2 FOR 32) <> $1
            ORDER BY id
            LIMIT $2
            FOR UPDATE
            ",
        )
        .bind(keys.active_key_id().as_slice())

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Inspect `SELECT operation FROM execution_payload_state WHERE component='signed_transactions'` and resolve whatever maintenance operation is in progress (complete or roll it back to 'ready' or 'rewrap').
  2. Ensure only one maintenance process runs at a time — the advisory/table lock (`lock_execution_payload_operation`) only excludes other lock-aware processes, not manual edits.
  3. If the value was written by an incompatible/older tool, run that tool's completion path or reset operation to 'ready' once storage is verified consistent.
  4. Confirm all adapter instances use a version that shares the same operation vocabulary ('ready'/'rewrap').

Example fix

// before: DB row in unexpected state
UPDATE execution_payload_state SET operation='paused' WHERE component='signed_transactions';
-- after: keep operation within the supported vocabulary
UPDATE execution_payload_state SET operation='ready', updated_at=NOW() WHERE component='signed_transactions';
Defensive patterns

Strategy: validation

Validate before calling

let operation: String = sqlx::query_scalar("SELECT operation FROM execution_payload_state WHERE component = 'signed_transactions'")
    .fetch_one(&mut *tx).await?;
if !matches!(operation.as_str(), "ready" | "rewrap") {
    return Err(anyhow!("payload storage in unsupported maintenance state: {operation}"));
}

Prevention

When it happens

Trigger: A concurrent or previous rewrap/maintenance operation left `execution_payload_state.operation` set to a value other than 'ready' or 'rewrap' (e.g. a custom/failed maintenance marker), and a batch rewrap call is made against that state.

Common situations: An operator manually updated `execution_payload_state.operation` to another value during an intervention; a crashed or older tool version wrote an unknown operation value; two adapter versions disagree on the set of valid operation strings in the same database.

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


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