nautechsystems/nautilus_trader · error · anyhow::Error
Failed to update execution intent {intent_id}: {e}
Error message
Failed to update execution intent {intent_id}: {e} What it means
Wrapped sqlx error from the UPDATE execution_intent SET status = $2, active = $3 statement in record_execution_status (database.rs:3667-3679), which advances the intent's status and computes the active flag after a receipt observation. The row was already locked FOR UPDATE earlier in the same transaction, so lock contention on this specific statement is unlikely; failures are typically connection loss, statement timeout, or a constraint violation on the status/active columns.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:3679
.map_err(|e| anyhow::anyhow!("Failed to update execution hash {transaction_hash}: {e}"))?;
anyhow::ensure!(
hash_result.rows_affected() == 1,
"Execution transaction hash {transaction_hash} was not found for intent {intent_id}"
);
sqlx::query(
"
UPDATE execution_intent
SET status = $2, active = $3, updated_at = NOW()
WHERE id = $1
",
)
.bind(intent_id)
.bind(status.as_str())
.bind(active)
.execute(&mut *transaction)
.await
.map_err(|e| anyhow::anyhow!("Failed to update execution intent {intent_id}: {e}"))?;
let transition_key = format!(
"{}:{transaction_hash}:{}:{}",
status.as_str(),
block_number.map_or_else(|| "none".to_string(), |value| value.to_string()),
block_hash.unwrap_or("none")
);
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
ON CONFLICT (intent_id, transition_key) DO NOTHING
",View on GitHub (pinned to 2114cf6f76)
Solutions
- Read the {e} cause: downcast to sqlx::Error and inspect as_database_error() for the failing constraint or SQLSTATE
- Apply pending migrations so execution_intent matches the status/active/updated_at columns
- Retry the whole call on transient classes (connection, 40001/40P01/57014); the enclosing transaction rolled back so the retry is idempotent
- If a CHECK/domain constraint rejected the status string, fix the TransactionStatus value being passed at the call site
Defensive patterns
Strategy: retry
Type guard
fn is_transient_db_error(err: &anyhow::Error) -> bool {
err.downcast_ref::<sqlx::Error>().map_or(false, |e| {
matches!(e, sqlx::Error::PoolTimedOut | sqlx::Error::PoolClosed | sqlx::Error::Io(_))
|| e.as_database_error().and_then(|d| d.code()).map_or(false, |c| {
matches!(c.as_ref(), "40001" | "40P01" | "55P03" | "57014" | "08000" | "08003" | "08006")
})
})
} Try / catch
match db.record_execution_status(...).await {
Ok(()) => {}
Err(e) if is_transient_db_error(&e) => retry_with_backoff(e), // rollback makes replay safe
Err(e) => return Err(e),
} Prevention
- Keep execution_intent migrations current, especially status CHECK constraints and the active column
- Use the typed TransactionStatus enum end-to-end instead of ad-hoc strings so only valid statuses reach the UPDATE
- Short transactions reduce the window where this statement can be killed by a failover
When it happens
Trigger: The database connection dying between the hash UPDATE and the intent UPDATE; a CHECK constraint on execution_intent.status rejecting the bound status string; schema drift where the active or updated_at column is missing; a serialization failure aborting the transaction at this point.
Common situations: Postgres restart or failover mid-transaction; running against a schema from an older migration set that lacks the active column; a status enum/domain on the column that does not include the value being written.
Related errors
- Failed to update execution hash {transaction_hash}: {e}
- Failed to record execution transition: {e}
- Failed to start replacement transaction persistence: {e}
- Failed to retire replaced execution hash: {e}
- Failed to mark execution intent replaced: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21).
Data as JSON: /api/errors/0b078a5c16d42d7a.
Report an issue: GitHub.