nautechsystems/nautilus_trader · critical · anyhow::Error

Failed to insert into execution_transaction table: {e}

Error message

Failed to insert into execution_transaction table: {e}

What it means

add_execution_transaction (crates/adapters/blockchain/src/cache/database.rs:2985) persists each signed on-chain transaction to the execution_transaction table before broadcast, so a signed transaction is never lost. The raw sqlx error is wrapped with this generic message; the actual cause is in {e}: connection failure, missing table/schema (migrations not applied), permission denied, constraint violation, or bind/type errors.

Source

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

            ON CONFLICT (chain_id, transaction_hash)
            DO UPDATE SET transaction_hash = EXCLUDED.transaction_hash
            WHERE execution_transaction.wallet_address = EXCLUDED.wallet_address
              AND execution_transaction.nonce = EXCLUDED.nonce
              AND execution_transaction.purpose = EXCLUDED.purpose
              AND execution_transaction.status = EXCLUDED.status
              AND execution_transaction.client_order_id IS NOT DISTINCT FROM EXCLUDED.client_order_id
        ",
        )
        .bind(chain_id as i32)
        .bind(wallet_address)
        .bind(nonce as i64)
        .bind(transaction_hash)
        .bind(purpose)
        .bind(status)
        .bind(client_order_id)
        .execute(&self.pool)
        .await
        .map_err(|e| anyhow::anyhow!("Failed to insert into execution_transaction table: {e}"))?;

        anyhow::ensure!(
            result.rows_affected() == 1,
            "Execution transaction {transaction_hash} conflicts with its persisted record"
        );
        Ok(())
    }

    /// Installs execution schema version 2 without changing existing transaction rows.
    ///
    /// The migration locks the legacy transaction table, refuses unresolved version 1 rows,
    /// installs the versioned intent and hash-history tables, and fences older writers before
    /// releasing the lock. This prevents a mixed-version process from bypassing the new signer
    /// ownership constraints.
    ///
    /// # Errors
    ///
    /// Returns an error if the database operation fails.

View on GitHub (pinned to 2114cf6f76)

Solutions

  1. Read the embedded sqlx error {e} - it distinguishes connection refused, 'relation ... does not exist', permission denied, and constraint violations.
  2. Run the blockchain cache migrations so execution_transaction exists in the target schema.
  3. Verify connectivity, credentials, and privileges for the signer's database role.
  4. Treat persistence failure as fatal before broadcast: do not broadcast a transaction that could not be recorded; halt submission and alert.
Defensive patterns

Strategy: retry

Validate before calling

// Pre-flight: confirm the table is reachable and present before the trading session
let row: (i64,) = sqlx::query_as("SELECT count(*) FROM execution_transaction")
    .fetch_one(&pool)
    .await?; // fails fast on missing table or connection

Try / catch

match db.add_execution_transaction(...).await {
    Ok(()) => {}
    Err(e) if is_transient(&e) => {
        // retry with backoff; still do NOT broadcast until persistence succeeds
        retry_with_backoff(|| db.add_execution_transaction(...)).await?
    }
    Err(e) => {
        log::error!("persistence failed, aborting broadcast: {e}");
        return Err(e);
    }
}

Prevention

When it happens

Trigger: Calling add_execution_transaction while Postgres is unreachable or restarting; before the blockchain cache schema migration created execution_transaction; with a DB role lacking INSERT; or with parameter values violating column constraints/types (e.g. chain_id beyond i32, oversized strings).

Common situations: Deploying the blockchain adapter without running its schema migrations; misconfigured Postgres host/credentials/pool; transient network drops between signer and database; Postgres restarted mid-session leaving stale connections.

Related errors


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