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
- Read the embedded sqlx error {e} - it distinguishes connection refused, 'relation ... does not exist', permission denied, and constraint violations.
- Run the blockchain cache migrations so execution_transaction exists in the target schema.
- Verify connectivity, credentials, and privileges for the signer's database role.
- 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
- Run the blockchain cache schema migrations before starting the signer.
- Fail fast on connectivity/permission problems with a pre-flight query at startup.
- Never broadcast a transaction whose persistence record failed; treat this error as a stop-the-line condition.
- Parse the embedded sqlx error to separate transient (connection) from permanent (schema/privilege) causes.
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
- Execution schema version {} is newer than supported version
- Execution transaction {transaction_hash} conflicts with its
- Failed to update execution hash {transaction_hash}: {e}
- Execution transaction hash {transaction_hash} was not found
- Failed to update execution intent {intent_id}: {e}
AI-assisted analysis of nautechsystems/nautilus_trader@2114cf6f76 (2026-08-21).
Data as JSON: /api/errors/68217c373c99e0cb.
Report an issue: GitHub.