{"record":{"id":"42e19d321e6d4c86","repo":"nautechsystems/nautilus_trader","slug":"restored-transaction-purpose-is-inconsistent","errorCode":null,"errorMessage":"Restored transaction purpose is inconsistent","messagePattern":"Restored transaction purpose is inconsistent","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/execution/client.rs","lineNumber":1388,"sourceCode":"            if intent.status == \"finalized\" {\n                InclusionOutcome::Finalized(included)\n            } else {\n                InclusionOutcome::Reverted(included)\n            }\n        } else {\n            executor.await_finality(&prepared).await?\n        };\n\n        match outcome {\n            InclusionOutcome::Finalized(mut included) => {\n                let trace_purpose = match (&plan, purpose) {\n                    (Some(plan), TransactionPurpose::Swap) => match plan.order.order_side() {\n                        OrderSide::Sell => \"swap_sell\",\n                        OrderSide::Buy => \"swap_buy\",\n                    },\n                    (None, TransactionPurpose::Wrap) => \"wrap\",\n                    (None, TransactionPurpose::Approve) => \"approve\",\n                    _ => anyhow::bail!(\"Restored transaction purpose is inconsistent\"),\n                };\n                included.finality.decisions.extend(\n                    verify_finalized_transaction(\n                        &included,\n                        &intent,\n                        nonce,\n                        &prepared.raw_tx,\n                        &executor,\n                        trace_purpose,\n                    )\n                    .await?,\n                );\n\n                if let Some(plan) = plan {\n                    let fill = validate_finalized_swap_fill(&plan, &included)?;\n                    let wallet =\n                        load_verified_wallet_after_fill(&plan, &included, &executor).await?;\n                    if !finality_already_committed {","sourceCodeStart":1370,"sourceCodeEnd":1406,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/18893faf8b356be3320add8de2f861b0b647cf06/crates/adapters/blockchain/src/execution/client.rs#L1370-L1406","documentation":"After a restored transaction finalizes, the client maps the (restored swap plan, purpose) pair to a trace purpose string ('swap_sell', 'swap_buy', 'wrap', 'approve') for finality verification. This bail fires when the combination matches none of the valid shapes — e.g. a Swap purpose with no restored plan, or a Wrap/Approve purpose with a plan — signalling corrupted or inconsistent persisted reconciliation state.","triggerScenarios":"connect() → reconcile_unresolved_execution() on a finalized intent where the persisted purpose and the restored plan disagree: purpose == Swap but restore_swap_plan returned no plan, or purpose == Wrap/Approve while a swap plan exists for the intent.","commonSituations":"Database rows for the intent and its swap plan written by different versions of the software; a swap plan that failed to persist while the intent recorded Swap purpose; manual database edits or partial restores; restore logic returning None for a plan that should exist.","solutions":["Inspect the execution database rows for the failing intent: confirm the purpose field and whether a swap plan row exists; they must agree (Swap ⇔ plan present, Wrap/Approve ⇔ no plan).","Re-run or repair the swap plan persistence so restore_swap_plan() returns the plan for Swap-purposed intents.","Check for a version mismatch between the code that wrote the intent and the code restoring it; upgrade/migrate the database schema to the current version.","Restore the affected intent rows from a consistent backup if the state is corrupted."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Verify purpose/plan consistency before reconnecting\nfn purpose_plan_consistent(purpose: &TransactionPurpose, plan: &Option<SwapPlan>) -> bool {\n    match purpose {\n        TransactionPurpose::Swap => plan.is_some(),\n        _ => plan.is_none(),\n    }\n}","typeGuard":"fn restore_shape_is_valid(purpose: &TransactionPurpose, plan: &Option<SwapPlan>) -> bool {\n    matches!((plan, purpose),\n        (Some(_), TransactionPurpose::Swap)\n        | (None, TransactionPurpose::Wrap)\n        | (None, TransactionPurpose::Approve))\n}","tryCatchPattern":"match client.connect().await {\n    Err(e) if e.to_string().contains(\"purpose is inconsistent\") => {\n        log::error!(\"corrupt persisted reconciliation state: {e}\");\n        // halt connect; repair DB rows or restore from backup\n    }\n    result => result?,\n}","preventionTips":["Persist the intent and its swap plan atomically in one transaction so they can never disagree.","Run database schema migrations in lockstep with client upgrades.","Never hand-edit execution database rows; use the provided recovery tooling."],"tags":["blockchain","reconciliation","state-inconsistency","database"],"backgroundTag":"internal-invariant-violation","analyzedSha":"18893faf8b356be3320add8de2f861b0b647cf06","analyzedAt":"2026-09-08T20:49:34.690Z","contentChangedAt":"2026-09-08T20:49:34.690Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}