nautechsystems/nautilus_trader · error · anyhow::Error

Protected payload keys are not initialized; connect the clie

Error message

Protected payload keys are not initialized; connect the client first

What it means

transaction_executor() clones the payload_keys set (protected encryption keys used when persisting execution payloads). These are initialized during connect(); if missing, transaction construction cannot safely persist the intent, so the client raises this error alongside the signer check.

Source

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

    fn payload_policy(&self) -> PayloadPolicy {
        PayloadPolicy {
            chain_id: self.chain.chain_id,
            signer: self.wallet_address,
            gas_limit: self.config.gas_limit,
            max_fee_per_gas: self.config.max_fee_per_gas_wei,
        }
    }

    fn transaction_executor(&self) -> anyhow::Result<TransactionExecutor> {
        let database = self.cache.database.clone().ok_or_else(|| {
            anyhow::anyhow!("No durable store configured; refusing to submit a transaction")
        })?;
        let signer = self
            .signer
            .clone()
            .ok_or_else(|| anyhow::anyhow!("Signer not initialized; connect the client first"))?;
        let payload_keys = self.payload_keys.clone().ok_or_else(|| {
            anyhow::anyhow!("Protected payload keys are not initialized; connect the client first")
        })?;
        let verification_config = self
            .config
            .verification
            .as_ref()
            .expect("verification config validated at construction");
        let identities = std::iter::once(&verification_config.authoritative)
            .chain(
                verification_config
                    .verifiers
                    .iter()
                    .map(|provider| &provider.identity),
            )
            .collect::<Vec<_>>();

        Ok(TransactionExecutor {
            http_rpc_client: self.http_rpc_client.clone(),
            verification: self.verification.clone(),

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Ensure client.connect() completes before submitting transactions.
  2. Run protect_payload_storage() once (disconnected) so a key set exists to load on connect.
  3. If connect failed, fix the key-store/database error and reconnect.
  4. Gate order submission behind post-connect readiness.

Example fix

// before
if !client.is_connected() { client.connect().await?; }
client.submit_order(order).await?; // may still race connect internals
// after
client.connect().await?;
anyhow::ensure!(client.is_connected(), "client not connected");
client.submit_order(order).await?;
Defensive patterns

Strategy: validation

Validate before calling

anyhow::ensure!(client.is_connected(), "connect first so payload keys and signer are initialized");
client.submit_order(order).await?;

Try / catch

if let Err(e) = client.submit_order(order).await {
    if e.to_string().contains("payload keys are not initialized") {
        client.connect().await?;
        client.submit_order(order).await?;
    } else { return Err(e.into()); }
}

Prevention

When it happens

Trigger: Calling wrap(), approve(), submit_order(), or reconcile_unresolved_execution() before connect() initialized self.payload_keys, or when keys were never loaded because no key set is persisted.

Common situations: Same lifecycle mistakes as the signer error: orders submitted pre-connect; partial initialization after failed connect; fresh database never protected so no keys were loaded.

Related errors


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