{"record":{"id":"3c0f5ecb5559d664","repo":"nautechsystems/nautilus_trader","slug":"execution-payload-storage-is-in-operation-mainte-3c0f5e","errorCode":null,"errorMessage":"Execution payload storage is in {operation} maintenance, not ready for rollback","messagePattern":"Execution payload storage is in (.+?) maintenance, not ready for rollback","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":5601,"sourceCode":"            \"ready\" => {\n                sqlx::query(\n                    \"ALTER TABLE execution_transaction_hash \\\n                     DROP CONSTRAINT IF EXISTS execution_transaction_payload_protected_check\",\n                )\n                .execute(&mut *transaction)\n                .await\n                .context(\"failed to open execution payload rollback representation\")?;\n                sqlx::query(\n                    \"UPDATE execution_payload_state \\\n                     SET operation = 'rollback', progress_id = 0, updated_at = NOW() \\\n                     WHERE component = 'signed_transactions'\",\n                )\n                .execute(&mut *transaction)\n                .await\n                .context(\"failed to record execution payload rollback state\")?;\n            }\n            \"rollback\" => {}\n            operation => anyhow::bail!(\n                \"Execution payload storage is in {operation} maintenance, not ready for rollback\"\n            ),\n        }\n        transaction\n            .commit()\n            .await\n            .context(\"failed to commit execution payload rollback state\")?;\n        Ok(())\n    }\n\n    async fn rollback_execution_payload_batch(\n        &self,\n        keys: &PayloadKeySet,\n        batch_size: i64,\n    ) -> anyhow::Result<bool> {\n        let mut transaction = self\n            .pool\n            .begin()","sourceCodeStart":5583,"sourceCodeEnd":5619,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L5583-L5619","documentation":"begin_execution_payload_rollback converts protected payload storage back to its unprotected representation. It accepts state.operation of 'ready' (start a new rollback) or 'rollback' (resume an interrupted one); any other maintenance value (e.g. 'migrate' or 'rewrap') makes rollback unsafe because payloads are in another transitional representation. The library bails so operators cannot interleave conflicting maintenance modes.","triggerScenarios":"Calling the rollback command (begin_execution_payload_rollback) while execution_payload_state.operation is 'migrate' or 'rewrap' — for example trying to disable protection while the initial encryption migration is still running, or while an active key rotation is in progress.","commonSituations":"Operator attempted to roll back protection before the initial migration finished; a key rotation was started by another process and rollback was issued concurrently; resume scripts invoked rollback while rotation tooling still held the state; misread state table led to ordering mistakes.","solutions":["Finish the current operation first: drain 'migrate' batches to ready or complete the 'rewrap' rotation, then start the rollback","If the goal is to abort a rotation, use the appropriate rotation tooling to finish/cancel it so state returns to 'ready' before rollback","Check SELECT operation FROM execution_payload_state to confirm the phase and coordinate with whoever/whatever started it","Schedule protection changes in a single serialized maintenance window"],"exampleFix":"// before: rollback during active rewrap\nbegin_execution_payload_rollback(&keys).await?;\n// after: let rotation finish, then roll back\nfinish_rewrap_to_ready(&keys).await?; // operation == 'ready'\nbegin_execution_payload_rollback(&keys).await?;","handlingStrategy":"validation","validationCode":"let op: String = sqlx::query_scalar(\n    \"SELECT operation FROM execution_payload_state WHERE component = 'signed_transactions'\")\n    .fetch_one(&pool).await?;\nanyhow::ensure!(matches!(op.as_str(), \"ready\" | \"rollback\"),\n    \"cannot roll back while storage operation is '{op}'\");","typeGuard":"fn rollback_allowed(operation: &str) -> bool {\n    matches!(operation, \"ready\" | \"rollback\")\n}","tryCatchPattern":"match db.begin_execution_payload_rollback(&keys).await {\n    Err(e) if e.to_string().contains(\"not ready for rollback\") => {\n        // let migrate/rewrap finish to 'ready', then retry rollback\n    }\n    r => r?,\n}","preventionTips":["Wait for migrations/rotations to reach 'ready' before initiating rollback","Use an advisory lock so rollback cannot interleave with rotation tooling","Monitor execution_payload_state for non-ready operations older than expected","Plan protection removal as the final step of a serialized maintenance window"],"tags":["rust","database","encryption","rollback","maintenance"],"backgroundTag":"invalid-state-transition","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}