{"record":{"id":"92c65125dbd532e8","repo":"nautechsystems/nautilus_trader","slug":"cannot-safely-migrate-unresolved-legacy-unresolv","errorCode":null,"errorMessage":"Cannot safely migrate {unresolved_legacy} unresolved execution schema version 1 transaction(s); resolve them with the prior version before enabling version {EXECUTION_SCHEMA_VERSION}","messagePattern":"Cannot safely migrate (.+?) unresolved execution schema version 1 transaction\\(s\\); resolve them with the prior version before enabling version (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/adapters/blockchain/src/cache/database.rs","lineNumber":3248,"sourceCode":"            && installed_version > EXECUTION_SCHEMA_VERSION\n        {\n            anyhow::bail!(\n                \"Execution schema version {} is newer than supported version {EXECUTION_SCHEMA_VERSION}\",\n                installed_version\n            );\n        }\n\n        let unresolved_legacy = sqlx::query_scalar::<_, i64>(\n            \"\n            SELECT COUNT(*)\n            FROM execution_transaction\n            WHERE status IN ('pending', 'included', 'reverted')\n            \",\n        )\n        .fetch_one(&mut *transaction)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to inspect legacy execution transactions: {e}\"))?;\n        anyhow::ensure!(\n            unresolved_legacy == 0,\n            \"Cannot safely migrate {unresolved_legacy} unresolved execution schema version 1 transaction(s); resolve them with the prior version before enabling version {EXECUTION_SCHEMA_VERSION}\"\n        );\n\n        for statement in [\n            \"\n            CREATE OR REPLACE FUNCTION execution_transaction_v2_fence()\n            RETURNS TRIGGER AS $$\n            BEGIN\n                RAISE EXCEPTION 'Legacy execution writer refused after schema version 2 activation';\n            END;\n            $$ LANGUAGE plpgsql\n            \",\n            \"DROP TRIGGER IF EXISTS execution_transaction_v2_fence ON execution_transaction\",\n            \"\n            CREATE TRIGGER execution_transaction_v2_fence\n            BEFORE INSERT OR UPDATE OR DELETE ON execution_transaction\n            FOR EACH STATEMENT EXECUTE FUNCTION execution_transaction_v2_fence()","sourceCodeStart":3230,"sourceCodeEnd":3266,"githubUrl":"https://github.com/nautechsystems/nautilus_trader/blob/2114cf6f761429e0adb5ca9596fcd7b895b16011/crates/adapters/blockchain/src/cache/database.rs#L3230-L3266","documentation":"A deliberate fail-closed guard in ensure_execution_transaction_schema: the migration refuses to activate schema v2 while any legacy execution_transaction row is still in status pending, included, or reverted. Those rows are v1 executions whose outcome is not settled from the v2 signer-ownership model's perspective; migrating past them would strand them behind the execution_transaction_v2_fence trigger that rejects legacy writers.","triggerScenarios":"Upgrading the binary while a v1 transaction is still pending; a v1 transaction stuck in included or reverted that never reached a fully settled state; a previous crash left pending rows behind.","commonSituations":"Node killed mid-execution and then upgraded; upgrading without draining in-flight transactions; stale rows from test wallets in a shared database.","solutions":["Start the previous binary version and let it drive the outstanding transactions to a settled state, then re-run the migration","Where on-chain state confirms settlement, move the legacy rows out of pending/included/reverted with a reviewed manual UPDATE, then re-run","Delete legacy rows that belong to discarded test wallets after verifying nothing references them"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"-- Run before upgrading; a non-zero count means the migration will refuse\nSELECT status, COUNT(*) FROM execution_transaction\nWHERE status IN ('pending', 'included', 'reverted')\nGROUP BY status;","typeGuard":null,"tryCatchPattern":"match db.ensure_execution_transaction_schema().await {\n    Err(e) if e.to_string().contains(\"Cannot safely migrate\") => {\n        // drain or settle legacy rows with the prior binary, then retry the upgrade\n    }\n    other => other?,\n}","preventionTips":["Drain in-flight transactions (let them settle) before deploying a schema upgrade","Include the unresolved-row count in pre-upgrade checklists and deployment runbooks","Never bypass the guard by deleting live pending rows without on-chain verification","Keep the previous binary version available to finish settling legacy state"],"tags":["rust","sqlx","postgresql","migration","fail-closed","data-migration-guard"],"backgroundTag":"schema-migration-blocked","analyzedSha":"2114cf6f761429e0adb5ca9596fcd7b895b16011","analyzedAt":"2026-08-21T11:28:30.864Z","schemaVersion":2},"datasetVersion":"2026-08-22T04:17:13.399Z"}