{"record":{"id":"1037ceb1f9838f36","repo":"nautechsystems/nautilus_trader","slug":"execution-payload-protection-is-active-but-no-pay","errorCode":null,"errorMessage":"Execution payload protection is active, but no payload key is configured","messagePattern":"Execution payload protection is active, but no payload key is configured","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":5173,"sourceCode":"                    \"Unsupported execution payload protection version {version}\"\n                );\n                let state_row = sqlx::query(\n                    \"SELECT deployment_id, protocol_version, operation, active_key_id \\\n                     FROM execution_payload_state WHERE component = 'signed_transactions' FOR SHARE\",\n                )\n                .fetch_optional(&mut *transaction)\n                .await\n                .context(\"failed to lock execution payload state\")?\n                .ok_or_else(|| anyhow::anyhow!(\"Execution payload state is missing\"))?;\n                let state = execution_payload_state_from_row(&state_row)?;\n                validate_execution_payload_state(&state, keys)?;\n                anyhow::ensure!(\n                    state.operation == \"ready\",\n                    \"Execution payload storage is not ready\"\n                );\n                Some(state.deployment_id)\n            }\n            (Some(_), None) => anyhow::bail!(\n                \"Execution payload protection is active, but no payload key is configured\"\n            ),\n        };\n\n        let mut cursor = 0_i64;\n        let mut plaintext_rows = 0_u64;\n        let mut original_rows = 0_u64;\n        let mut replacement_rows = 0_u64;\n        let mut authenticated_rows = 0_u64;\n        let mut key_ids = BTreeSet::new();\n\n        loop {\n            let rows = sqlx::query_as::<_, ExecutionTransactionHashRow>(\n                \"\n                SELECT\n                    id, intent_id, chain_id, transaction_hash, payload_expected,\n                    raw_transaction, sealed_transaction, status, block_number, block_hash,\n                    receipt_success, gas_used, effective_gas_price, current","sourceCodeStart":5155,"sourceCodeEnd":5191,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L5155-L5191","documentation":"inspect_execution_payload_storage validates that when the execution payload protection marker exists in execution_schema_version, a PayloadKeySet must also be supplied so persisted sealed payloads can be authenticated. The (Some(_), None) arm fires when protection is active in the database but the caller passed no keys. Without the payload key there is no way to decrypt or verify stored signed transactions, so the check aborts.","triggerScenarios":"Calling inspect_execution_payload_storage (or its wrappers such as require_execution_payload_storage / maintenance checks) with keys = None against a database where the execution payload protection marker row exists — i.e. a previously protected deployment being opened without configured payload keys.","commonSituations":"Operator omitted the payload key/passphrase from config after enabling encryption; environment variable holding the key not set in the new deployment; connecting a fresh tool or shell session to a protected production database without loading keys; config rollback removed the key while the database kept protection.","solutions":["Provide the configured PayloadKeySet (load payload keys via the key provider/passphrase used when protection was activated) to the inspect/require call","If protection is no longer wanted, first run the payload rollback procedure with the correct keys to return storage to ready/unprotected, then inspect without keys","Verify the key source (env var, KMS, config file) is present in this environment; do not open protected databases from shells lacking the key"],"exampleFix":"// before\nlet (check, _tx) = db.inspect_execution_payload_storage(None, Some(policy), batch).await?;\n// after\nlet keys = load_payload_keys()?; // fetch configured payload key set\nlet (check, _tx) = db.inspect_execution_payload_storage(Some(&keys), Some(policy), batch).await?;","handlingStrategy":"validation","validationCode":"let protected: Option<i16> = sqlx::query_scalar(\n    \"SELECT version FROM execution_schema_version WHERE component = $1\")\n    .bind(\"component_id\") // EXECUTION_PAYLOAD_COMPONENT\n    .fetch_optional(&pool).await?;\nanyhow::ensure!(keys.is_some() || protected.is_none(),\n    \"payload protection active: configure payload keys before inspecting\");","typeGuard":"fn keys_available_for(protected_db: bool, keys: Option<&PayloadKeySet>) -> Option<&PayloadKeySet> {\n    if protected_db { keys } else { None.or(keys) }\n}","tryCatchPattern":"match db.inspect_execution_payload_storage(keys_opt, policy, batch).await {\n    Err(e) if e.to_string().contains(\"no payload key is configured\") => {\n        // load keys from KMS/env and retry once\n    }\n    r => r?,\n}","preventionTips":["Keep the payload key provider configured wherever the database is accessed, including ops shells and tooling","Fail fast at config load when the DB has protection enabled but no key is set","Do not remove key config while the protection marker exists; roll back protection first","Document key sourcing (env var/KMS) in runbooks for protected deployments"],"tags":["rust","database","encryption","missing-key","config"],"backgroundTag":"missing-api-key","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}