nautechsystems/nautilus_trader · error · anyhow::Error

Intent cannot make the verified finality transition

Error message

Intent cannot make the verified finality transition

What it means

A state-machine guard: after locking the intent, the code ensure()s that the stored nonce matches the finality nonce and that `execution_transition_allowed(&current_status, finality.status)` permits the requested transition. Either the nonce is stale/wrong or the intent is in a status from which the target verified-finality status is not reachable. This prevents duplicate, out-of-order, or illegal finality transitions.

Source

Thrown at crates/adapters/blockchain/src/cache/database.rs:7058

        }

        let (current_status, intent_nonce, fill_emitted, terminal_emitted) =
            sqlx::query_as::<_, (String, Option<i64>, bool, bool)>(
                "
                SELECT status, nonce, fill_emitted, terminal_emitted
                FROM execution_intent
                WHERE id = $1 AND chain_id = $2 AND wallet_address = $3 AND active
                FOR UPDATE
                ",
            )
            .bind(finality.intent_id)
            .bind(chain_id)
            .bind(finality.wallet_address)
            .fetch_optional(&mut *transaction)
            .await
            .map_err(|e| anyhow::anyhow!("Failed to lock intent for verified finality: {e}"))?
            .ok_or_else(|| anyhow::anyhow!("Active finality intent was not found"))?;
        anyhow::ensure!(
            intent_nonce == Some(nonce)
                && execution_transition_allowed(&current_status, finality.status),
            "Intent cannot make the verified finality transition"
        );

        for (index, decision) in finality.decisions.iter().enumerate() {
            let height_start = decision
                .height_start
                .map(i64::try_from)
                .transpose()
                .context("Verification height exceeds PostgreSQL BIGINT")?;
            let height_end = decision
                .height_end
                .map(i64::try_from)
                .transpose()
                .context("Verification height exceeds PostgreSQL BIGINT")?;
            let transition_key = format!(
                "finality:{}:{}:{index}",

View on GitHub (pinned to 18893faf8b)

Solutions

  1. Log current_status, finality.status, intent_nonce and expected nonce to see which condition failed
  2. If the event was already applied, treat it as a duplicate and skip (the transition already happened)
  3. Re-derive the nonce on the finality message and confirm it matches the intent's stored nonce
  4. Check execution_transition_allowed's transition table covers the observed current→target status pair
  5. Ensure single-writer ordering for finality events per intent (or make application idempotent upstream)

Example fix

// before
anyhow::ensure!(
    intent_nonce == Some(nonce)
        && execution_transition_allowed(&current_status, finality.status),
    "Intent cannot make the verified finality transition"
);
// after
anyhow::ensure!(
    intent_nonce == Some(nonce),
    "Intent nonce mismatch: stored={intent_nonce:?} finality={nonce}"
);
anyhow::ensure!(
    execution_transition_allowed(&current_status, finality.status),
    "Intent cannot make the verified finality transition: {} -> {}",
    current_status, finality.status
);
Defensive patterns

Strategy: type-guard

Validate before calling

// Guard the transition before calling the API
fn can_transition(current: &Status, target: &Status) -> bool {
    execution_transition_allowed(current, target)
}
if !can_transition(&current_status, &finality.status) {
    // duplicate or out-of-order event: skip instead of failing
}

Type guard

fn is_applicable_finality(current_status: &Status, finality: &VerifiedFinality, stored_nonce: Option<i64>, nonce: i64) -> bool {
    stored_nonce == Some(nonce)
        && execution_transition_allowed(current_status, &finality.status)
}

Try / catch

match apply_verified_finality(...).await {
    Err(e) if e.to_string().contains("verified finality transition") => {
        // treat as duplicate/out-of-order delivery
        info!("finality transition not applicable for intent {}", finality.intent_id);
        Ok(())
    }
    other => other,
}

Prevention

When it happens

Trigger: Applying the same finality event twice (idempotency guard hit); finality arriving after the intent already moved to a terminal status; a nonce mismatch from replaying an older finality message; a code/config change that reordered statuses so the transition is no longer in the allowed map.

Common situations: At-least-once delivery from the event source re-delivering a processed finality event; two workers processing finality concurrently where the second sees an already-transitioned status; upgrading the adapter while historical events with old nonces are still in flight; mismatched nonce derivation between the intent creator and the finality verifier.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08). Data as JSON: /api/errors/4839d55b839a63b8. Report an issue: GitHub.