{"record":{"id":"328bb77ef4f89921","repo":"nautechsystems/nautilus_trader","slug":"failed-to-lock-migrated-intent-e","errorCode":null,"errorMessage":"Failed to lock migrated intent: {e}","messagePattern":"Failed to lock migrated intent: (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":4252,"sourceCode":"                        })?;\n                        let gas_used = i64::try_from(record.gas_used.ok_or_else(|| {\n                            anyhow::anyhow!(\"Terminal migration record has no gas usage\")\n                        })?)\n                        .context(\"Migration gas usage exceeds PostgreSQL BIGINT\")?;\n                        let receipt_success = record.receipt_success.ok_or_else(|| {\n                            anyhow::anyhow!(\"Terminal migration record has no receipt status\")\n                        })?;\n                        anyhow::ensure!(\n                            receipt_success == (status == TransactionStatus::Finalized),\n                            \"Migration receipt status conflicts with terminal status\"\n                        );\n                        let current_status = sqlx::query_scalar::<_, String>(\n                            \"SELECT status FROM execution_intent WHERE id = $1 FOR UPDATE\",\n                        )\n                        .bind(record.intent_id)\n                        .fetch_one(&mut *transaction)\n                        .await\n                        .map_err(|e| anyhow::anyhow!(\"Failed to lock migrated intent: {e}\"))?;\n                        let hash_result = sqlx::query(\n                            \"\n                            UPDATE execution_transaction_hash\n                            SET status = $3, block_number = $4, block_hash = $5,\n                                receipt_success = $6, gas_used = $7,\n                                effective_gas_price = $8, updated_at = NOW()\n                            WHERE intent_id = $1 AND transaction_hash = $2 AND current\n                              AND payload_expected\n                            \",\n                        )\n                        .bind(record.intent_id)\n                        .bind(transaction_hash)\n                        .bind(status.as_str())\n                        .bind(block_number)\n                        .bind(block_hash)\n                        .bind(receipt_success)\n                        .bind(gas_used)\n                        .bind(record.effective_gas_price.as_deref())","sourceCodeStart":4234,"sourceCodeEnd":4270,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L4234-L4270","documentation":"This error wraps any sqlx failure from `SELECT status FROM execution_intent WHERE id = $1 FOR UPDATE` during the verification migration that reconstructs terminal transaction state. It fires when the intent row cannot be locked/read inside the migration transaction — most often because the row does not exist (query_scalar expects exactly one row) or the SELECT fails (connection, aborted transaction, or SQL error). The underlying database error is interpolated into the message as {e}.","triggerScenarios":"Running the verification migration when (1) record.intent_id has no row in execution_intent (fetch_one on an empty result -> RowNotFound), (2) the migration transaction was already aborted by an earlier failed statement or hits a serialization/deadlock failure on the FOR UPDATE lock under concurrent access, (3) the DB connection drops mid-transaction, or (4) the execution_intent table is missing/renamed in the target database.","commonSituations":"Migrating evidence that references intents hard-deleted from the DB; running the migration concurrently from two workers causing deadlocks on the row lock; pointing the migration at a database with an older/missing schema; transient network blips to Postgres during a long migration batch.","solutions":["Check that every intent_id in the migration evidence exists in execution_intent before running the migration (SELECT id FROM execution_intent WHERE id = ANY($1)).","Run the migration from a single worker/instance only, so FOR UPDATE locks cannot deadlock.","Inspect the interpolated {e} in the log: RowNotFound means a missing intent row — fix the evidence or restore the row; 'current transaction is aborted' means an earlier statement in this transaction failed.","Verify the target database has the expected schema (\\d execution_intent) and that you are connected to the intended database.","If the cause was a transient connection error, re-run the migration; the transaction rollback leaves state consistent."],"exampleFix":"// before: migration assumes all evidence intent_ids exist\nmigrate_records(records).await?;\n\n// after: pre-validate evidence against the DB\nlet missing = sqlx::query_scalar::<_, String>(\n    \"SELECT id FROM unnest($1::text[]) AS t(id) WHERE id NOT IN (SELECT id FROM execution_intent)\",\n).bind(&intent_ids).fetch_all(&pool).await?;\nanyhow::ensure!(missing.is_empty(), \"evidence references missing intents: {missing:?}\");","handlingStrategy":"validation","validationCode":"let exists = sqlx::query_scalar::<_, i64>(\n    \"SELECT COUNT(*) FROM execution_intent WHERE id = $1\",\n).bind(&record.intent_id).fetch_one(&pool).await?;\nif exists == 0 {\n    anyhow::bail!(\"intent {} missing from execution_intent; fix evidence before migrating\", record.intent_id);\n}","typeGuard":"fn migration_record_has_existing_intent(record: &MigrationRecord, intent_ids: &HashSet<String>) -> bool {\n    intent_ids.contains(&record.intent_id)\n}","tryCatchPattern":"match migrate_records(records).await {\n    Err(e) if e.to_string().contains(\"Failed to lock migrated intent\") => {\n        tracing::error!(\"migration lock failed (missing row or concurrent migration): {e:#}\");\n        // do not blindly retry: check evidence/DB first, then retry once\n    }\n    Err(e) => return Err(e),\n    Ok(()) => {}\n}","preventionTips":["Pre-validate that every intent_id in migration evidence exists before starting the migration.","Run the migration from a single worker/instance to avoid FOR UPDATE deadlocks.","Run the migration inside a maintenance window with no concurrent writers.","Check the interpolated underlying sqlx error: RowNotFound means a missing intent row."],"tags":["database","postgres","migration","sqlx","row-locking"],"backgroundTag":"database-query-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"}