nautechsystems/nautilus_trader · critical · anyhow::Error

Signed transaction envelope does not use the database active

Error message

Signed transaction envelope does not use the database active key

What it means

This error is raised during protected persistence of a sealed (encrypted) signed transaction. The library locks the execution_payload_state row and requires that the envelope's embedded key id matches the database's active_key_id. If the caller signed the envelope with a rotated, stale, or foreign key, the transaction is rejected so plaintext or wrongly-keyed payloads never reach storage.

Source

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

                anyhow::anyhow!("Failed to start signed transaction persistence: {e}")
            })?;

        if let Some(envelope) = sealed_transaction {
            let state_row = sqlx::query(
                "SELECT deployment_id, protocol_version, operation, active_key_id \
                 FROM execution_payload_state WHERE component = 'signed_transactions' FOR SHARE",
            )
            .fetch_optional(&mut *transaction)
            .await
            .context("failed to lock execution payload state for protected persistence")?
            .ok_or_else(|| anyhow::anyhow!("Execution payload protection is not active"))?;
            let state = execution_payload_state_from_row(&state_row)?;
            anyhow::ensure!(
                state.protocol_version == EXECUTION_PAYLOAD_PROTOCOL_VERSION
                    && state.operation == "ready",
                "Execution payload storage is not ready for protected persistence"
            );
            anyhow::ensure!(
                envelope_key_id(envelope)?.as_slice() == state.active_key_id.as_slice(),
                "Signed transaction envelope does not use the database active key"
            );
        } else {
            let marker = sqlx::query_scalar::<_, bool>(
                "SELECT EXISTS (SELECT 1 FROM execution_schema_version WHERE component = $1)",
            )
            .bind(EXECUTION_PAYLOAD_COMPONENT)
            .fetch_one(&mut *transaction)
            .await
            .context("failed to inspect execution payload marker")?;
            anyhow::ensure!(
                !marker,
                "Plaintext signed transaction persistence is disabled after payload activation"
            );
        }
        let current_status = sqlx::query_scalar::<_, String>(
            "SELECT status FROM execution_intent WHERE id = $1 FOR UPDATE",

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Refresh the active key id from execution_payload_state (SELECT active_key_id ...) and re-seal the envelope before retrying persistence.
  2. Verify the process is connected to the intended database/environment; compare deployment_id and active_key_id with the target DB.
  3. If a rotation happened mid-flight, run the key-rotation/roll procedure so local signing material matches the new active key.
  4. Retry after re-sealing; do not persist the envelope under the old key.

Example fix

// before
let envelope = seal_with(cached_key_id, payload); // stale key
// after
let active = load_active_key_id(pool).await?;
let envelope = seal_with(active, payload); // re-seal with DB active key
Defensive patterns

Strategy: validation

Validate before calling

let state: (Vec<u8>,) = sqlx::query_as("SELECT active_key_id FROM execution_payload_state WHERE component='signed_transactions'").fetch_one(&pool).await?;
anyhow::ensure!(envelope_key_id(&envelope)?.as_slice() == state.0.as_slice(), "envelope key id != DB active key; re-seal before persisting");

Type guard

fn uses_active_key(envelope: &[u8], active_key_id: &[u8]) -> bool {
    envelope_key_id(envelope).map(|k| k.as_slice() == active_key_id).unwrap_or(false)
}

Try / catch

match db.add_execution_transaction(intent_id, chain_id, hash, sealed).await {
    Err(e) if e.to_string().contains("does not use the database active key") => {
        refresh_active_key(&pool).await?;
        let resealed = seal(payload, active_key_id).await?;
        db.add_execution_transaction(intent_id, chain_id, hash, resealed).await?;
    }
    result => result?,
}

Prevention

When it happens

Trigger: Calling add_execution_transaction (or add_execution_transaction_payload with sealed_transaction=Some) while the envelope was encrypted with a key other than execution_payload_state.active_key_id for component 'signed_transactions'. Typically the DB was key-rotated (active_key_id changed) after the caller obtained/cached the old signing key, or the caller is writing to a different database than the one whose key produced the envelope.

Common situations: Key rotation performed on the DB between envelope creation and persistence; multiple environments (staging vs prod) sharing a transaction flow; a replica/mismatched connection pointing at a database with a different active key; process restart with a stale in-memory key cache.

Understand the failure class

Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — 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/f369d348ec2403e2. Report an issue: GitHub.