nautechsystems/nautilus_trader · error · anyhow::Error
Stored execution payload requires unavailable key {}
Error message
Stored execution payload requires unavailable key {} What it means
After deriving the key ID from each stored envelope header, the code requires that key to be present in the configured set of available payload keys. A stored payload encrypted with a key the operator has not provisioned cannot be decrypted, so the validation refuses to continue and names the missing key ID.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:7558
) -> anyhow::Result<()> {
let envelopes = sqlx::query_scalar::<_, Vec<u8>>(
"SELECT DISTINCT substring(sealed_transaction FROM 1 FOR 33) \
FROM execution_transaction_hash \
WHERE sealed_transaction IS NOT NULL",
)
.fetch_all(&mut **transaction)
.await
.context("failed to inspect execution payload key inventory")?;
for header in envelopes {
anyhow::ensure!(
header.len() == 33,
"Stored execution payload has a truncated envelope header"
);
let mut envelope = header;
envelope.extend_from_slice(&[0; 12 + 16]);
let key_id = envelope_key_id(&envelope)?;
anyhow::ensure!(
keys.contains_key(&key_id),
"Stored execution payload requires unavailable key {}",
alloy::hex::encode(key_id)
);
}
Ok(())
}
async fn load_execution_intent(
transaction: &mut Transaction<'_, Postgres>,
intent_id: i64,
) -> anyhow::Result<ExecutionIntentRow> {
sqlx::query_as::<_, ExecutionIntentRow>(
"
SELECT
id, schema_version, chain_id, wallet_address, nonce, purpose, status,
client_order_id, trader_id, strategy_id, account_id, instrument_id,
pool_address, transaction_to, transaction_input, transaction_value,View on GitHub (pinned to 18893faf8b)
Solutions
- Provision the missing key (hex key ID shown in the message) into the configured key set
- Re-encrypt or purge payloads sealed with retired keys as part of the rotation procedure
- Keep old keys available (archived) until all payloads they sealed are expired or re-sealed
Defensive patterns
Strategy: validation
Validate before calling
let required: Vec<[u8;32]> = derive_required_key_ids(&stored_envelopes)?;
let missing: Vec<_> = required.iter().filter(|k| !keys.contains_key(k)).collect();
if !missing.is_empty() { provision_keys(missing)?; } Prevention
- Retain retired keys (archived) until all payloads they sealed expire
- Provision the complete key set, not just the current active key, on new nodes
- Keep key material synchronized across replicas sharing the database
When it happens
Trigger: Validating stored execution payloads when at least one envelope's key ID is absent from the provided key map — e.g. after key rotation removed an old key still referenced by stored data.
Common situations: Retiring/rotating keys without retaining old keys needed to read historical payloads; provisioning a new node with only the current key while the DB holds older envelopes; divergent key sets between replicas.
Related errors
- Execution payload protection is active, but no payload key i
- Execution payload storage is in {operation} maintenance; com
- Execution payload storage is in {operation} maintenance, not
- Execution payload storage is in {operation} maintenance, not
- Protected execution transaction {} contains plaintext
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/57c24cadc761e00b.
Report an issue: GitHub.