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
- Ensure client.connect() completes before submitting transactions.
- Run protect_payload_storage() once (disconnected) so a key set exists to load on connect.
- If connect failed, fix the key-store/database error and reconnect.
- 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
- Protect payload storage once at setup so keys persist for later connects.
- Gate all submission paths on post-connect readiness.
- Verify key loading in connect logs after each restart.
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
- Active execution intent {intent_id} was not found
- Failed to load active execution intent: {e}
- Failed to start replacement transaction persistence: {e}
- Failed to lock active execution intent {intent_id}: {e}
- Invalid execution transition for intent {intent_id}: {curren
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/9a5f97a0df39cc48.
Report an issue: GitHub.