nautechsystems/nautilus_trader · error · anyhow::Error
Active execution intent {intent_id} was not found
Error message
Active execution intent {intent_id} was not found What it means
Raised in add_execution_replacement_hash (database.rs:3800) when the locking SELECT ... WHERE id = $1 AND active returns no row: the intent either does not exist or is no longer active. The active flag is flipped to false by terminal processing (record_execution_status sets active=false once finalized/reverted and both event markers are emitted, and mark_execution_event_emitted deactivates on terminal markers), so 'not found' here usually means the intent already completed.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:3800
pub async fn add_execution_replacement_hash(
&self,
intent_id: i64,
chain_id: u32,
transaction_hash: &str,
) -> anyhow::Result<ExecutionTransactionHashRow> {
let chain_id_db = i32::try_from(chain_id)
.with_context(|| format!("Chain ID {chain_id} exceeds PostgreSQL INTEGER"))?;
let mut transaction = self.pool.begin().await.map_err(|e| {
anyhow::anyhow!("Failed to start replacement transaction persistence: {e}")
})?;
let current_status = sqlx::query_scalar::<_, String>(
"SELECT status FROM execution_intent WHERE id = $1 AND active FOR UPDATE",
)
.bind(intent_id)
.fetch_optional(&mut *transaction)
.await
.map_err(|e| anyhow::anyhow!("Failed to lock active execution intent {intent_id}: {e}"))?
.ok_or_else(|| anyhow::anyhow!("Active execution intent {intent_id} was not found"))?;
anyhow::ensure!(
execution_transition_allowed(¤t_status, TransactionStatus::Replaced),
"Invalid execution transition for intent {intent_id}: {current_status} -> replaced"
);
sqlx::query(
"
UPDATE execution_transaction_hash
SET current = FALSE, status = 'replaced', updated_at = NOW()
WHERE intent_id = $1 AND current
",
)
.bind(intent_id)
.execute(&mut *transaction)
.await
.map_err(|e| anyhow::anyhow!("Failed to retire replaced execution hash: {e}"))?;
let row = sqlx::query_as::<_, ExecutionTransactionHashRow>(View on GitHub (pinned to 2114cf6f76)
Solutions
- Check the intent's actual state: SELECT status, active, fill_emitted, terminal_emitted FROM execution_intent WHERE id = $1
- If the intent is finalized/reverted, treat the replacement observation as stale and skip it (the transaction never started mutating anything)
- If the id simply does not exist, fix the caller that produced it (re-resolve via get_active_execution_intent instead of caching ids)
- If active=false but status is non-terminal, investigate what deactivated the row before overriding anything
Example fix
// before: a late replacement observation crashes the watcher
let row = db.add_execution_replacement_hash(intent_id, chain_id, &hash).await?;
// after: treat 'no active intent' as a benign stale event
match db.add_execution_replacement_hash(intent_id, chain_id, &hash).await {
Ok(row) => Ok(Some(row)),
Err(e) if e.to_string().contains("was not found") => Ok(None), // intent already completed
Err(e) => Err(e),
} Defensive patterns
Strategy: validation
Validate before calling
// pre-check: is the intent still active before recording a late replacement?
let row = sqlx::query_as::<_, (bool,)>("SELECT active FROM execution_intent WHERE id = $1")
.bind(intent_id)
.fetch_optional(&pool)
.await?;
if !row.is_some_and(|(active,)| active) {
// intent absent or completed: skip the stale replacement event
return Ok(None);
} Try / catch
match db.add_execution_replacement_hash(intent_id, chain_id, &hash).await {
Ok(row) => Ok(Some(row)),
Err(e) if e.to_string().contains("was not found") => Ok(None), // stale: already terminal/inactive
Err(e) => Err(e),
} Prevention
- In replacement/finality races, tolerate the loser's write failing with not-found instead of crashing the watcher
- Do not cache intent state across restarts; re-read active status when replaying queued events
- Design event consumers so out-of-order delivery is a skip, not an error path
When it happens
Trigger: Recording a replacement hash after the intent was finalized and its fill/terminal event was marked emitted (active=false); passing an intent_id that was never created or belongs to another database; the intent deactivated by a concurrent transaction that committed first.
Common situations: A reorg/replacement race where the finality watcher wins and the replacement watcher arrives late; replaying queued replacement events after a restart against an intent that finished meanwhile; mixed-up intent ids when several wallets trade the same pool.
Related errors
- Execution transaction hash {transaction_hash} was not found
- Failed to update execution hash {transaction_hash}: {e}
- Failed to update execution intent {intent_id}: {e}
- Failed to record execution transition: {e}
- Failed to commit execution transition: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21).
Data as JSON: /api/errors/c7a5d944f505e21b.
Report an issue: GitHub.