nautechsystems/nautilus_trader · error · anyhow::Error
Cannot safely migrate {unresolved_legacy} unresolved executi
Error message
Cannot safely migrate {unresolved_legacy} unresolved execution schema version 1 transaction(s); resolve them with the prior version before enabling version {EXECUTION_SCHEMA_VERSION} What it means
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.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:3248
&& installed_version > EXECUTION_SCHEMA_VERSION
{
anyhow::bail!(
"Execution schema version {} is newer than supported version {EXECUTION_SCHEMA_VERSION}",
installed_version
);
}
let unresolved_legacy = sqlx::query_scalar::<_, i64>(
"
SELECT COUNT(*)
FROM execution_transaction
WHERE status IN ('pending', 'included', 'reverted')
",
)
.fetch_one(&mut *transaction)
.await
.map_err(|e| anyhow::anyhow!("Failed to inspect legacy execution transactions: {e}"))?;
anyhow::ensure!(
unresolved_legacy == 0,
"Cannot safely migrate {unresolved_legacy} unresolved execution schema version 1 transaction(s); resolve them with the prior version before enabling version {EXECUTION_SCHEMA_VERSION}"
);
for statement in [
"
CREATE OR REPLACE FUNCTION execution_transaction_v2_fence()
RETURNS TRIGGER AS $$
BEGIN
RAISE EXCEPTION 'Legacy execution writer refused after schema version 2 activation';
END;
$$ LANGUAGE plpgsql
",
"DROP TRIGGER IF EXISTS execution_transaction_v2_fence ON execution_transaction",
"
CREATE TRIGGER execution_transaction_v2_fence
BEFORE INSERT OR UPDATE OR DELETE ON execution_transaction
FOR EACH STATEMENT EXECUTE FUNCTION execution_transaction_v2_fence()View on GitHub (pinned to 2114cf6f76)
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
Defensive patterns
Strategy: validation
Validate before calling
-- Run before upgrading; a non-zero count means the migration will refuse
SELECT status, COUNT(*) FROM execution_transaction
WHERE status IN ('pending', 'included', 'reverted')
GROUP BY status; Try / catch
match db.ensure_execution_transaction_schema().await {
Err(e) if e.to_string().contains("Cannot safely migrate") => {
// drain or settle legacy rows with the prior binary, then retry the upgrade
}
other => other?,
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: Node killed mid-execution and then upgraded; upgrading without draining in-flight transactions; stale rows from test wallets in a shared database.
Related errors
- Failed to start execution schema migration: {e}
- Failed to lock legacy execution transactions: {e}
- Failed to migrate execution_transaction table: {e}
- Failed to read execution schema version: {e}
- Failed to inspect legacy execution transactions: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21).
Data as JSON: /api/errors/92c65125dbd532e8.
Report an issue: GitHub.