{"record":{"id":"da87f634c57f9523","repo":"nautechsystems/nautilus_trader","slug":"failed-to-lock-recoverable-execution-intent-e","errorCode":null,"errorMessage":"Failed to lock recoverable execution intent: {e}","messagePattern":"Failed to lock recoverable execution intent: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":3439,"sourceCode":"        Ok(())\n    }\n\n    /// Releases an intent when no broadcast attempt can have occurred.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the intent advanced to broadcast or persistence fails.\n    pub async fn mark_execution_intent_recoverable(&self, intent_id: i64) -> anyhow::Result<()> {\n        let mut transaction = self.pool.begin().await.map_err(|e| {\n            anyhow::anyhow!(\"Failed to start recoverable execution transition: {e}\")\n        })?;\n        let current_status = sqlx::query_scalar::<_, String>(\n            \"SELECT status FROM execution_intent WHERE id = $1 FOR UPDATE\",\n        )\n        .bind(intent_id)\n        .fetch_optional(&mut *transaction)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to lock recoverable execution intent: {e}\"))?\n        .ok_or_else(|| anyhow::anyhow!(\"Execution intent {intent_id} was not found\"))?;\n        anyhow::ensure!(\n            matches!(current_status.as_str(), \"prepared\" | \"signed\"),\n            \"Execution intent {intent_id} is {current_status}, not recoverable before broadcast\"\n        );\n        let result = sqlx::query(\n            \"\n            UPDATE execution_intent\n            SET status = 'recoverable', active = FALSE, updated_at = NOW()\n            WHERE id = $1 AND status IN ('prepared', 'signed')\n            \",\n        )\n        .bind(intent_id)\n        .execute(&mut *transaction)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to mark execution intent recoverable: {e}\"))?;\n        anyhow::ensure!(\n            result.rows_affected() == 1,","sourceCodeStart":3421,"sourceCodeEnd":3457,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/2114cf6f761429e0adb5ca9596fcd7b895b16011/crates/adapters/blockchain/src/cache/database.rs#L3421-L3457","documentation":"Thrown when the SELECT status ... FOR UPDATE that serializes the recoverable transition fails in mark_execution_intent_recoverable. That row lock contends with record_execution_status and add_execution_transaction_hash touching the same intent, so the wrapped error is commonly 'lock timeout' or 'deadlock detected', or a dropped connection.","triggerScenarios":"Releasing an intent at the same moment a receipt observation locks it in record_execution_status; lock_timeout exceeded while waiting on FOR UPDATE; connection drop during the lock wait.","commonSituations":"Signer, broadcaster, and watcher actors operating on one intent concurrently; deadlock-prone access orderings.","solutions":["Retry with backoff - FOR UPDATE waits are transient by nature","Take the recoverable transition before enabling watchers on the intent, or drain them first","Raise lock_timeout if the contention window is legitimately long"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for attempt in 0..3 {\n    match db.mark_execution_intent_recoverable(intent_id).await {\n        Ok(()) => break,\n        Err(e) => {\n            let msg = e.to_string();\n            if msg.contains(\"lock timeout\") || msg.contains(\"deadlock\") {\n                tokio::time::sleep(Duration::from_millis(50u64 << attempt)).await;\n            } else {\n                return Err(e);\n            }\n        }\n    }\n}","preventionTips":["Serialize all writes for one intent through a single task or actor","Take recoverable transitions before watchers begin recording statuses on the intent","Set lock_timeout to a small value with retry rather than waiting indefinitely"],"tags":["rust","sqlx","postgresql","row-lock","deadlock","recovery"],"backgroundTag":"database-query-failed","analyzedSha":"2114cf6f761429e0adb5ca9596fcd7b895b16011","analyzedAt":"2026-08-21T11:28:30.864Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}