nautechsystems/nautilus_trader · error
Active replacement scan intent was not found
Error message
Active replacement scan intent was not found
What it means
After validating the nonce ledger, `record_execution_replacement_scan` locks the `execution_intent` row matching (intent_id, chain_id, wallet_address, nonce) that is still `active`, using `FOR UPDATE`. If no such row exists the scan has no live intent to attach evidence to, so the transaction fails with this error.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:6291
"Replacement scan conflicts with the canonical nonce or manifest ledger"
);
let current_status = sqlx::query_scalar::<_, String>(
"
SELECT status
FROM execution_intent
WHERE id = $1 AND chain_id = $2 AND wallet_address = $3
AND nonce = $4 AND active
FOR UPDATE
",
)
.bind(scan.intent_id)
.bind(chain_id)
.bind(scan.wallet_address)
.bind(nonce)
.fetch_optional(&mut *transaction)
.await
.context("failed to lock the replacement scan intent")?
.ok_or_else(|| anyhow::anyhow!("Active replacement scan intent was not found"))?;
if let Some(cursor) = scan.finalized_cursor {
let number = i64::try_from(cursor.number)
.context("Replacement scan cursor exceeds PostgreSQL BIGINT")?;
let durable_hash = sqlx::query_scalar::<_, String>(
"
SELECT hash
FROM execution_verified_finalized_header
WHERE chain_id = $1 AND wallet_address = $2 AND number = $3
",
)
.bind(chain_id)
.bind(scan.wallet_address)
.bind(number)
.fetch_optional(&mut *transaction)
.await
.context("failed to validate replacement cursor against finalized headers")?
.ok_or_else(|| {View on GitHub (pinned to 18893faf8b)
Solutions
- Confirm the intent still exists and `active = TRUE` in `execution_intent` for the exact (intent_id, chain_id, wallet_address, nonce) tuple.
- Do not resubmit a scan for an intent that has already been finalized or replaced; treat this as a no-op in the caller.
- Refresh the intent id from the current submission pipeline instead of reusing a cached one.
- Check that the nonce bound to the intent matches the scan nonce.
Example fix
// before: unconditional resubmission of a completed scan
if let Err(e) = db.record_execution_replacement_scan(&scan).await { retry(e); }
// after: check the intent is still active first
if db.is_execution_intent_active(scan.intent_id).await? {
db.record_execution_replacement_scan(&scan).await?;
} Defensive patterns
Strategy: validation
Validate before calling
let active = sqlx::query_scalar::<_, bool>("SELECT active FROM execution_intent WHERE id = $1 AND chain_id = $2 AND wallet_address = $3 AND nonce = $4").bind(scan.intent_id).bind(chain_id).bind(scan.wallet_address).bind(scan.nonce as i64).fetch_optional(&pool).await?;
if active != Some(true) { skip_scan(); } Type guard
async fn intent_is_active(pool: &PgPool, intent_id: i64, chain_id: i32, wallet: &str, nonce: i64) -> anyhow::Result<bool> {
Ok(sqlx::query_scalar::<_, bool>("SELECT active FROM execution_intent WHERE id=$1 AND chain_id=$2 AND wallet_address=$3 AND nonce=$4")
.bind(intent_id).bind(chain_id).bind(wallet).bind(nonce).fetch_optional(pool).await?.unwrap_or(false))
} Try / catch
match db.record_execution_replacement_scan(&scan).await {
Err(e) if e.to_string().contains("Active replacement scan intent was not found") => info!("intent already finalized; skipping"),
Err(e) => return Err(e),
Ok(()) => {},
} Prevention
- Do not cache intent ids across scan runs; reload the active intent before each submission.
- Treat a missing active intent as a terminal no-op, not a retryable failure.
- Keep intent lifecycle transitions and scan submission in the same serialized pipeline.
When it happens
Trigger: Calling `record_execution_replacement_scan` with an `intent_id` that does not exist, that belongs to a different chain_id/wallet_address/nonce, or whose `active` flag is FALSE (already finalized, replaced, or deactivated).
Common situations: The intent was already marked replaced/recoverable by a prior scan run; a stale intent id was cached by the caller after an earlier scan completed; the scan payload was constructed against a re-keyed wallet or different chain.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- Execution payload storage is not rolling back
- Execution intent {intent_id} is not prepared for nonce {nonc
- Execution intent {} was not found
- Replacement scan conflicts with the canonical nonce or manif
- Replacement scan cursor regressed or changed
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/6d4e592ecf439611.
Report an issue: GitHub.