nautechsystems/nautilus_trader · error · anyhow::Error

Failed to inspect legacy execution transactions: {e}

Error message

Failed to inspect legacy execution transactions: {e}

What it means

Thrown when the COUNT(*) over legacy execution_transaction rows with status in ('pending','included','reverted') fails inside ensure_execution_transaction_schema. The table was locked ACCESS EXCLUSIVE moments earlier, so the failure is transport-level: dropped connection, statement timeout scanning a very large table, or the backend being terminated by an admin.

Source

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

        if let Some(installed_version) = installed_version
            && 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

View on GitHub (pinned to 2114cf6f76)

Solutions

  1. Re-run the migration once connectivity is confirmed stable
  2. Temporarily raise statement_timeout for the migration session
  3. Archive or trim legacy execution_transaction rows before upgrading
Defensive patterns

Strategy: retry

Validate before calling

-- Estimate scan cost before upgrading
SELECT reltuples::bigint AS approx_rows FROM pg_class WHERE relname = 'execution_transaction';

Try / catch

match db.ensure_execution_transaction_schema().await {
    Err(e) if e.to_string().contains("statement timeout") || e.to_string().contains("canceling statement") => {
        // raise statement_timeout for the session and retry once
    }
    other => other?,
}

Prevention

When it happens

Trigger: A large legacy execution_transaction table combined with a low statement_timeout; pg_terminate_backend invoked while the count runs; network interruption while the exclusive lock is held.

Common situations: Long-lived nodes with years of transaction history; timeout values tuned for short OLTP queries.

Related errors


AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21). Data as JSON: /api/errors/85fa0a748d0449ee. Report an issue: GitHub.