nautechsystems/nautilus_trader · error · anyhow::Error
Failed to reconstruct migrated intent: {e}
Error message
Failed to reconstruct migrated intent: {e} What it means
This error wraps sqlx failures from `UPDATE execution_intent SET status = $2, updated_at = NOW() WHERE id = $1`, the step that moves the locked migrated intent to its terminal status (finalized/reverted) after the hash row was reconstructed. It fires only when the UPDATE errors at the database level — not when it affects zero rows, since the intent row was already locked and verified earlier in the same transaction. The driver error is interpolated as {e}.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:4285
.bind(block_hash)
.bind(receipt_success)
.bind(gas_used)
.bind(record.effective_gas_price.as_deref())
.execute(&mut *transaction)
.await
.map_err(|e| anyhow::anyhow!("Failed to reconstruct migrated hash: {e}"))?;
anyhow::ensure!(
hash_result.rows_affected() == 1,
"Migrated terminal transaction hash was not found"
);
sqlx::query(
"UPDATE execution_intent SET status = $2, updated_at = NOW() WHERE id = $1",
)
.bind(record.intent_id)
.bind(status.as_str())
.execute(&mut *transaction)
.await
.map_err(|e| anyhow::anyhow!("Failed to reconstruct migrated intent: {e}"))?;
if current_status != status.as_str() {
sqlx::query(
"
INSERT INTO execution_transaction_transition (
intent_id, transaction_hash_id, transition_key,
from_status, to_status, block_number, block_hash
)
SELECT $1, id, $3, $4, $5, $6, $7
FROM execution_transaction_hash
WHERE intent_id = $1 AND transaction_hash = $2
",
)
.bind(record.intent_id)
.bind(transaction_hash)
.bind(format!("migration:{}:{transaction_hash}", status.as_str()))
.bind(current_status)
.bind(status.as_str())
.bind(block_number)View on GitHub (pinned to 18893faf8b)
Solutions
- Read the interpolated {e}; constraint violations name the offending column/constraint directly.
- Verify execution_intent.status accepts TransactionStatus::Finalized/Reverted as_str() values; align enum strings or schema.
- Check for transaction-aborted cascade: an earlier statement in this transaction failed; fix that first error in the logs.
- Retry the migration if the cause was a transient connection failure; the rollback keeps state consistent.
- Ensure no concurrent schema changes run during the migration window.
Example fix
// before: status passed straight through
.bind(status.as_str())
// after: guard against schema drift first
let s = status.as_str();
anyhow::ensure!(matches!(s, "finalized" | "reverted"), "unexpected terminal status {s}");
.bind(s) Defensive patterns
Strategy: try-catch
Validate before calling
// confirm the terminal status strings are accepted by the schema
let allowed: Vec<String> = sqlx::query_scalar(
"SELECT unnest(enum_range(NULL::execution_intent_status))::text",
).fetch_all(&pool).await?;
anyhow::ensure!(allowed.contains(&"finalized".to_string()) && allowed.contains(&"reverted".to_string()),
"schema does not accept terminal statuses: {allowed:?}"); Type guard
fn is_terminal_status(status: &TransactionStatus) -> bool {
matches!(status, TransactionStatus::Finalized | TransactionStatus::Reverted)
} Try / catch
if let Err(e) = run_migration(&pool, records).await {
let msg = format!("{e:#}");
if msg.contains("Failed to reconstruct migrated intent") {
// usually schema drift on execution_intent.status or an aborted transaction
tracing::error!("intent UPDATE failed: {msg}");
}
return Err(e); // rolled back; safe to fix and re-run
} Prevention
- Keep TransactionStatus::as_str() strings aligned with the DB enum/CHECK constraint on execution_intent.status.
- Apply schema migrations before data migrations in every environment.
- Retry only after diagnosing: transient connection errors are safe to retry (transaction rolls back).
- Watch for 'current transaction is aborted' — the real failure is an earlier statement.
When it happens
Trigger: The UPDATE fails due to: a CHECK constraint or enum on the status column rejecting the terminal status string, the transaction already being aborted by a prior failed statement, a connection loss mid-transaction, or conflicting locks from concurrent DDL.
Common situations: Schema drift where execution_intent.status allows different values than TransactionStatus::as_str() produces; DB connection timeout during a long migration batch; migration running while another deployment applies schema changes.
Related errors
- Failed to reconstruct migrated hash: {e}
- Failed to lock migrated intent: {e}
- Failed to persist migration evidence: {e}
- Failed to seed chain table: {e}
- Failed to call create_block_partition for chain {}: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/8206f51446285761.
Report an issue: GitHub.