nautechsystems/nautilus_trader · error

Protected payload keys are required for execution recovery

Error message

Protected payload keys are required for execution recovery

What it means

reconcile_unresolved_execution acquires an execution payload lease that protects specific payload keys (self.payload_keys) from concurrent modification during recovery. If payload_keys is not configured (None), the client cannot establish the lease and aborts connect. The library throws this because concurrent recovery without key protection could double-drive the same signed payloads.

Source

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

            weth: self.weth_address,
            token_in,
            token_out,
            fee,
            amount_in,
            min_amount_out: U256::ZERO,
            slippage_bps: 0,
            quote_spend_ceiling: None,
            profiler_position: None,
        })
    }

    async fn reconcile_unresolved_execution(&self) -> anyhow::Result<()> {
        let database = self.cache.database.clone().ok_or_else(|| {
            anyhow::anyhow!("No durable store configured for execution reconciliation")
        })?;
        let _payload_lease = database
            .acquire_execution_payload_lease(self.payload_keys.as_deref().ok_or_else(|| {
                anyhow::anyhow!("Protected payload keys are required for execution recovery")
            })?)
            .await?;
        let wallet_address = self.wallet_address.to_string();
        anyhow::ensure!(
            !database
                .has_recoverable_signed_execution(self.chain.chain_id, &wallet_address)
                .await?,
            "A recoverable execution for wallet {} retains signed transaction bytes; refusing to reuse its nonce without explicit recovery",
            self.wallet_address
        );
        let Some(intent) = database
            .get_active_execution_intent(self.chain.chain_id, &wallet_address)
            .await?
        else {
            return Ok(());
        };
        anyhow::ensure!(
            intent.schema_version == crate::execution::transaction::EXECUTION_SCHEMA_VERSION,

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Set the payload_keys configuration on the blockchain execution client to the keys protecting its execution payloads, then reconnect.
  2. Check adapter docs/config schema for the payload-keys (protected payload) option and supply the values used by your deployment.
  3. If constructing the client in code, populate the payload_keys field of the client's config/args instead of leaving it None.
  4. If this appears after an upgrade, diff your config against the new required fields and add the missing payload-keys entry.

Example fix

// before
ExecutionClientConfig(database=..., )  # payload_keys missing
// after
ExecutionClientConfig(database=..., payload_keys=["execution:signed_tx:0xWallet"])
Defensive patterns

Strategy: validation

Validate before calling

// Before connect, verify payload keys are configured
if config.payload_keys.as_deref().unwrap_or(&[]).is_empty() {
    panic!("payload_keys must be set for execution recovery");
}

Type guard

fn has_payload_keys(keys: &Option<Vec<String>>) -> bool {
    keys.as_ref().map(|k| !k.is_empty()).unwrap_or(false)
}

Prevention

When it happens

Trigger: connect() -> reconcile_unresolved_execution calls database.acquire_execution_payload_lease(self.payload_keys.as_deref()...) while self.payload_keys is None or empty. Occurs when the execution client is constructed without its protected payload keys configuration (e.g. keys for signed transaction payloads) yet durable reconciliation is enabled.

Common situations: Partial configuration of the blockchain execution client: database configured but payload-keys option omitted; building the client programmatically and skipping the payload_keys field; version/config drift where a new required option was added but not set in existing configs.

Understand the failure class

Background: "is required", "must be set", "missing required field": configuration validation errors across open-source libraries — this error's family across 36 libraries.

Related errors


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