{"record":{"id":"7f1279940c245a30","repo":"nautechsystems/nautilus_trader","slug":"invalid-execution-transition-for-intent-intent-id","errorCode":null,"errorMessage":"Invalid execution transition for intent {intent_id}: {current_status} -> {}","messagePattern":"Invalid execution transition for intent (.+?): (.+?) -> (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":6793,"sourceCode":"                \"Execution gas used {} exceeds PostgreSQL BIGINT\",\n                gas_used.unwrap_or_default()\n            )\n        })?;\n        let mut transaction = self\n            .pool\n            .begin()\n            .await\n            .map_err(|e| anyhow::anyhow!(\"Failed to start execution status transition: {e}\"))?;\n        let (current_status, fill_emitted, terminal_emitted) =\n            sqlx::query_as::<_, (String, bool, bool)>(\n            \"SELECT status, fill_emitted, terminal_emitted FROM execution_intent WHERE id = $1 FOR UPDATE\",\n        )\n        .bind(intent_id)\n        .fetch_optional(&mut *transaction)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to lock execution intent {intent_id}: {e}\"))?\n        .ok_or_else(|| anyhow::anyhow!(\"Execution intent {intent_id} was not found\"))?;\n        anyhow::ensure!(\n            execution_transition_allowed(&current_status, status),\n            \"Invalid execution transition for intent {intent_id}: {current_status} -> {}\",\n            status.as_str()\n        );\n\n        let active = match status {\n            TransactionStatus::Finalized | TransactionStatus::Reverted => {\n                !fill_emitted && !terminal_emitted\n            }\n            TransactionStatus::Recoverable => false,\n            _ => true,\n        };\n        let hash_result = sqlx::query(\n            \"\n            UPDATE execution_transaction_hash\n            SET status = $3,\n                block_number = COALESCE($4, block_number),\n                block_hash = COALESCE($5, block_hash),","sourceCodeStart":6775,"sourceCodeEnd":6811,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/cache/database.rs#L6775-L6811","documentation":"This error comes from anyhow::ensure! after the state machine check `execution_transition_allowed(&current_status, status)` fails. It means the requested status transition is not part of the allowed execution-intent lifecycle (e.g. Pending -> Finalized skipped intermediate states, or moving a terminal status). The transaction is aborted, leaving the stored status unchanged.","triggerScenarios":"Calling the transition method with a target status that is illegal from the row's current status — e.g. delivering a receipt/finality event twice, events arriving out of order, or the row already terminal (Filled/Reverted/Finalized) and another update arriving.","commonSituations":"Duplicate block/receipt processing after a node reconnect or replay; two workers racing on the same intent (one wins, the other's stale status check fails); a status enum/version change making old persisted statuses invalid for new transition rules; feeding reverted receipts into an intent expected to fill.","solutions":["Log/inspect current_status and the requested status; confirm the event matches the intent's actual lifecycle stage.","Make processing idempotent: skip transitions already applied (check fill_emitted/terminal_emitted flags before calling).","Deduplicate events upstream (track processed tx hashes/block numbers) to avoid double-delivery.","If this fires on replay after a version upgrade, review execution_transition_allowed for newly added/renamed statuses and migrate stale rows."],"exampleFix":"// before\nanyhow::ensure!(\n    execution_transition_allowed(&current_status, status),\n    \"Invalid execution transition for intent {intent_id}: {current_status} -> {}\",\n    status.as_str()\n);\n// after\nif current_status == status.as_str() || terminal_emitted {\n    tracing::debug!(%intent_id, %current_status, \"transition already applied; treating as idempotent no-op\");\n    transaction.commit().await?;\n    return Ok(());\n}\nanyhow::ensure!(\n    execution_transition_allowed(&current_status, status),\n    \"Invalid execution transition for intent {intent_id}: {current_status} -> {}\",\n    status.as_str()\n);","handlingStrategy":"validation","validationCode":"// Idempotency check before requesting a transition\nlet (current, fill_emitted, terminal_emitted) = fetch_intent_state(&pool, &intent_id).await?;\nif terminal_emitted || current == status.as_str() {\n    return Ok(()); // already applied; no-op\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = db.record_execution_status(&intent_id, status, ...).await {\n    if e.to_string().contains(\"Invalid execution transition\") {\n        tracing::debug!(%intent_id, \"stale/duplicate transition; treating as no-op\");\n        return Ok(());\n    }\n    return Err(e);\n}","preventionTips":["Track processed tx hashes/block numbers to deduplicate receipt events.","Single-writer per intent or rely on FOR UPDATE serialization.","Check fill_emitted/terminal_emitted flags before emitting duplicate transitions.","Review transition rules when upgrading status enums and migrate stale rows."],"tags":["state-machine","invalid-transition","idempotency","database"],"backgroundTag":"invalid-state-transition","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}