{"record":{"id":"6f128a0caefcf50e","repo":"nautechsystems/nautilus_trader","slug":"failed-to-start-recoverable-execution-transition","errorCode":null,"errorMessage":"Failed to start recoverable execution transition: {e}","messagePattern":"Failed to start recoverable execution transition: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":3431,"sourceCode":"        .bind(nonce_db)\n        .execute(&self.pool)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to assign nonce {nonce} to execution intent: {e}\"))?;\n        anyhow::ensure!(\n            result.rows_affected() == 1,\n            \"Execution intent {intent_id} is not prepared for nonce {nonce}\"\n        );\n        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')","sourceCodeStart":3413,"sourceCodeEnd":3449,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/2114cf6f761429e0adb5ca9596fcd7b895b16011/crates/adapters/blockchain/src/cache/database.rs#L3413-L3449","documentation":"Thrown when mark_execution_intent_recoverable fails at pool.begin(), before the intent is locked or inspected. The wrapped sqlx error means a connection could not be acquired (database unreachable, pool exhausted, dropped connection). No state changed when this fires.","triggerScenarios":"Releasing a pre-broadcast intent while the pool is fully consumed by other database work; database restart mid-operation; connection acquisition timing out under burst load.","commonSituations":"Load spikes exhausting the pool; failover of the database tier; connectivity blips.","solutions":["Verify database health and connectivity, then retry the release","Increase pool max_connections/acquire_timeout for peak concurrency","Schedule recovery sweeps outside peak activity windows"],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"match db.mark_execution_intent_recoverable(intent_id).await {\n    Err(e) if e.downcast_ref::<sqlx::Error>().is_some_and(|se| matches!(se, sqlx::Error::PoolTimedOut | sqlx::Error::Io(_))) => {\n        // retry after pool pressure subsides; nothing changed on failure\n    }\n    other => other?,\n}","preventionTips":["Run recovery sweeps with bounded concurrency against the same pool","Verify pool health before recovery passes that release many intents","Keep recovery logic idempotent so retries are always safe"],"tags":["rust","sqlx","postgresql","connection-pool","recovery"],"backgroundTag":"database-connection-failed","analyzedSha":"2114cf6f761429e0adb5ca9596fcd7b895b16011","analyzedAt":"2026-08-21T11:28:30.864Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}