nautechsystems/nautilus_trader · error
Failed to lock intent for verified action: {e}
Error message
Failed to lock intent for verified action: {e} What it means
Thrown when the SELECT that locks the active execution intent for a verified action (by intent_id, chain_id, wallet_address) fails with a database error. This is a query failure rather than a missing row; the transaction is aborted and no nonce or attempt state is read.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:6099
.ok_or_else(|| anyhow::anyhow!("Canonical nonce ledger is not initialized"))?;
anyhow::ensure!(
manifest_version == batch.manifest_version && manifest_digest == batch.manifest_digest,
"Verified action manifest identity changed"
);
let intent_nonce = sqlx::query_scalar::<_, Option<i64>>(
"
SELECT nonce
FROM execution_intent
WHERE id = $1 AND chain_id = $2 AND wallet_address = $3 AND active
FOR UPDATE
",
)
.bind(batch.intent_id)
.bind(chain_id)
.bind(batch.wallet_address)
.fetch_optional(&mut *transaction)
.await
.map_err(|e| anyhow::anyhow!("Failed to lock intent for verified action: {e}"))?
.ok_or_else(|| anyhow::anyhow!("Active verified-action intent was not found"))?;
anyhow::ensure!(
intent_nonce == Some(nonce),
"Verified action nonce does not match the active intent"
);
let attempt = sqlx::query_scalar::<_, i64>(
"
SELECT COUNT(*)
FROM execution_verification_decision
WHERE intent_id = $1 AND decision_class = $2
",
)
.bind(batch.intent_id)
.bind(batch.decision_class)
.fetch_one(&mut *transaction)
.await
.map_err(|e| anyhow::anyhow!("Failed to number verified action evidence: {e}"))?;
View on GitHub (pinned to 18893faf8b)
Solutions
- Retry the operation; the transaction rolls back cleanly and re-acquires the lock.
- Check Postgres logs for the underlying error (lock timeout, permission, connection drop).
- Reduce lock contention by shortening transactions that hold the intent row lock.
- Verify the database role can SELECT from the execution intent table.
Example fix
// before: no retry around lock acquisition
record_execution_verification_batch(&db, &batch).await?;
// after: retry on lock-related failures
match record_execution_verification_batch(&db, &batch).await {
Err(e) if is_lock_timeout(&e) => { tokio::time::sleep(Duration::from_millis(200)).await; record_execution_verification_batch(&db, &batch).await?; }
res => res?,
} Defensive patterns
Strategy: retry
Try / catch
// Rust
match record_batch().await {
Err(e) if e.to_string().contains("Failed to lock intent for verified action")
&& (is_lock_timeout(&e) || is_transient(&e)) => retry_with_backoff(record_batch),
res => res,
} Prevention
- Keep transactions that lock the intent row short.
- Set a modest lock_timeout so failures are fast and retryable.
- Serialize actions per intent (queue per intent_id) to avoid contention.
When it happens
Trigger: fetch_optional on the intent-locking SELECT returns Err — connection loss, statement timeout, permission error, or deadlock while the row lock is being acquired.
Common situations: Long-held locks by another transaction causing statement_timeout; database failover mid-query; missing SELECT grants on the intent table; proxy killing idle connections.
Understand the failure class
Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.
Related errors
- Failed to read verified action nonce ledger: {e}
- Implement FromRow for FuturesSpread
- Implement FromRow for OptionSpread
- Execution schema version {} is newer than supported version
- Verified finalized transaction count advanced without an act
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/305c04400c3b1593.
Report an issue: GitHub.