nautechsystems/nautilus_trader · error
Failed to record recoverable transition: {e}
Error message
Failed to record recoverable transition: {e} What it means
After successfully flipping the intent to 'recoverable', the code inserts an audit row into execution_transaction_transition (transition_key 'recoverable'); if that INSERT fails, the error "Failed to record recoverable transition: {e}" is raised. The whole transaction then rolls back, so the intent remains 'prepared' — the failure is atomic.
Source
Thrown at crates/adapters/blockchain/src/cache/database.rs:6553
.await
.map_err(|e| anyhow::anyhow!("Failed to mark execution intent recoverable: {e}"))?;
anyhow::ensure!(
result.rows_affected() == 1,
"Execution intent {intent_id} is not recoverable from preparation"
);
sqlx::query(
"
INSERT INTO execution_transaction_transition (
intent_id, transition_key, from_status, to_status
) VALUES ($1, 'recoverable', $2, 'recoverable')
ON CONFLICT (intent_id, transition_key) DO NOTHING
",
)
.bind(intent_id)
.bind(current_status)
.execute(&mut *transaction)
.await
.map_err(|e| anyhow::anyhow!("Failed to record recoverable transition: {e}"))?;
transaction
.commit()
.await
.map_err(|e| anyhow::anyhow!("Failed to commit recoverable transition: {e}"))?;
Ok(())
}
/// Persists a signed transaction and advances its intent before broadcast.
///
/// # Errors
///
/// Returns an error if the intent is not prepared, lacks a nonce, conflicts with a stored
/// hash, or persistence fails.
pub async fn add_execution_transaction_hash(
&self,
intent_id: i64,
chain_id: u32,
transaction_hash: &str,View on GitHub (pinned to 18893faf8b)
Solutions
- Read the wrapped sqlx error chain for the concrete constraint/message (e.g. column does not exist, foreign key violation).
- Verify the execution_transaction_transition schema matches the adapter's expected columns (intent_id, transition_key, from_status, to_status).
- Retry the operation after transient errors — the transaction rolled back atomically, so the intent stays 'prepared' and the transition is safe to redo.
- Check grants on the transition table and database health (disk, connections) if the failure repeats.
Defensive patterns
Strategy: retry
Try / catch
// Atomic rollback means safe retry after transient insert failures
match db.mark_execution_intent_recoverable(id).await {
Err(e) if is_transient_db_error(&e) => retry_with_backoff(id),
Err(e) => return Err(e),
Ok(()) => {},
} Prevention
- Keep the execution_transaction_transition schema in sync with adapter migrations.
- Verify INSERT grants on the audit table for the adapter's DB role.
- Retry transient errors — rollback leaves the intent 'prepared' and fully recoverable.
- Monitor audit-table growth and disk usage to avoid insert failures at scale.
When it happens
Trigger: The INSERT INTO execution_transaction_transition fails: constraint violation (e.g. a foreign key or NOT NULL on from_status), schema mismatch after a migration, connection loss, or deadlock — anything that makes sqlx's execute return Err.
Common situations: A migration changed execution_transaction_transition (renamed columns, added a required column) while the adapter runs older expectations; database connection dropped after long transaction hold; permissions revoked on the transition table; disk-full or tablespace errors on the audit table.
Related errors
- Failed to record signed transaction transition: {e}
- Failed to record execution transition: {e}
- Failed to insert into trade table: {e}
- Failed to insert into quote table: {e}
- Error executing statement {sql_statement} with error: {e:?}
AI-assisted analysis of nautechsystems/nautilus_trader@18893faf8b (2026-09-08).
Data as JSON: /api/errors/bdd0a5820c112ed0.
Report an issue: GitHub.