{"record":{"id":"eb7c2244f4886398","repo":"nautechsystems/nautilus_trader","slug":"failed-to-mark-execution-intent-recoverable-e","errorCode":null,"errorMessage":"Failed to mark execution intent recoverable: {e}","messagePattern":"Failed to mark execution intent recoverable: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":6536,"sourceCode":"        .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            current_status == \"prepared\",\n            \"Execution intent {intent_id} is {current_status}, not recoverable before signing\"\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 = 'prepared'\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,\n            \"Execution intent {intent_id} is not recoverable from preparation\"\n        );\n        sqlx::query(\n            \"\n            INSERT INTO execution_transaction_transition (\n                intent_id, transition_key, from_status, to_status\n            ) VALUES ($1, 'recoverable', $2, 'recoverable')\n            ON CONFLICT (intent_id, transition_key) DO NOTHING\n            \",\n        )\n        .bind(intent_id)\n        .bind(current_status)\n        .execute(&mut *transaction)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to record recoverable transition: {e}\"))?;\n        transaction","sourceCodeStart":6518,"sourceCodeEnd":6554,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L6518-L6554","documentation":"The UPDATE that flips execution_intent from 'prepared' to 'recoverable' failed at the database level; the underlying sqlx error is wrapped as \"Failed to mark execution intent recoverable: {e}\". This is a persistence failure, not a business-rule rejection (rows_affected is checked separately).","triggerScenarios":"The `UPDATE execution_intent SET status='recoverable' ...` statement inside the open transaction fails — connection drop mid-transaction, deadlock on the FOR UPDATE-locked row, statement timeout, or constraint/permission failure.","commonSituations":"Database connection pool exhausted or idle-timeout closed the connection while the transaction was held open; another long transaction deadlocked on the intent row; Postgres restart/failover during recovery; network partition between the adapter and the database.","solutions":["Inspect the wrapped sqlx error source for the root cause (deadlock, connection closed, timeout) via the anyhow chain.","Retry the whole mark_execution_intent_recoverable call with backoff — the failed transaction rolled back, so the state is unchanged and safe to redo.","Check database health: connection limits, max_connections, statement_timeout, and recent deadlock logs.","Reduce time spent holding the transaction open (avoid slow work between begin and commit) to lower deadlock/timeout risk."],"exampleFix":null,"handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"// Retry transient DB failures with backoff; transaction rolled back so state is safe\nfor attempt in 0..3 {\n    match db.mark_execution_intent_recoverable(id).await {\n        Ok(()) => break,\n        Err(e) if attempt < 2 && is_transient_db_error(&e) => tokio::time::sleep(backoff(attempt)).await,\n        Err(e) => return Err(e),\n    }\n}","preventionTips":["Keep pool settings (max_lifetime, idle_timeout) longer than the longest recovery transaction.","Monitor deadlocks and set a sane statement_timeout.","Avoid doing slow non-DB work while holding the transaction.","Use connection retries at the pool/infra layer for failovers."],"tags":["database","sql","connection","retryable"],"backgroundTag":"database-write-failed","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"}