tursodatabase/turso · error · InvalidOperationException
The transaction has completed.
Error message
The transaction has completed.
What it means
EnsureExecutable rejects execution when the command's transaction is finished: Transaction is { IsCompleted: true } or { WasRolledBackExternally: true } throws InvalidOperationException. Completion is set by Commit()/Rollback(), and external rollback happens when the connection reclaims an abandoned transaction; after that the native transaction context no longer exists and a statement would run in a misleading autocommit mode.
Source
Thrown at bindings/dotnet/src/Turso.Data.Sqlite/SqliteCommand.cs:597
throw new InvalidOperationException(Properties.Resources.SetRequiresNoOpenReader(property));
}
private void EnsureExecutable(string method)
{
if (_hasOpenReader)
throw new InvalidOperationException(Properties.Resources.DataReaderOpen);
if (Connection is null || Connection.State != ConnectionState.Open)
throw new InvalidOperationException(Properties.Resources.CallRequiresOpenConnection(method));
if (Transaction is { IsCompleted: true } or { WasRolledBackExternally: true })
throw new InvalidOperationException(Properties.Resources.TransactionCompleted);
if (Transaction is not null && !ReferenceEquals(Transaction.Connection, Connection))
throw new InvalidOperationException(Properties.Resources.TransactionConnectionMismatch);
var connectionTransaction = Connection.Transaction;
if (connectionTransaction is null || ReferenceEquals(Transaction, connectionTransaction))
return;
if (connectionTransaction.IsCompleted)
throw new InvalidOperationException(Properties.Resources.TransactionCompleted);
if (!IsTransactionControlCommand(CommandText))
throw new InvalidOperationException(Properties.Resources.TransactionRequired);
}
private void CloseReader()
{
_hasOpenReader = false;
Connection?.ReaderClosed();
}
internal Action OwnBufferedReader()
{
_hasOpenReader = true;
Connection?.ReaderOpened();
return () =>
{
CloseReader();
Dispose();View on GitHub (pinned to 6c72522679)
Solutions
- Begin a new transaction for further work after Commit()/Rollback().
- Scope command lifetimes inside the transaction's using block.
- After a connection-level failure, reopen and re-begin rather than reusing the old pair.
Example fix
// before tx.Commit(); cmd.ExecuteNonQuery(); // cmd still bound to the completed transaction -> throws // after tx.Commit(); using var tx2 = conn.BeginTransaction(); cmd.Transaction = tx2; cmd.ExecuteNonQuery();
Defensive patterns
Strategy: validation
Validate before calling
// completion is observable via the thrown error; track it locally instead
sealed class TxScope(SqliteConnection conn) {
SqliteTransaction? tx;
public bool Active => tx is not null;
public SqliteTransaction Begin() => tx = conn.BeginTransaction();
public void Finish() { if (tx is not null) { tx.Dispose(); tx = null; } }
}
if (scope.Active) cmd.ExecuteNonQuery(); Try / catch
catch (InvalidOperationException) when (transactionWasFinished) {
using var tx2 = conn.BeginTransaction();
cmd.Transaction = tx2;
cmd.ExecuteNonQuery();
} Prevention
- Treat transactions and their commands as one scope; dispose them together.
- Never execute from a command still bound to a committed or rolled-back transaction.
- Reset cmd.Transaction (or recreate commands) after Commit/Rollback.
When it happens
Trigger: Calling Commit() then reusing the same command/transaction for another statement; executing after Rollback() on an error path that falls through to more SQL; a transaction whose connection was closed or reset (externally rolled back); long-lived commands outliving their transaction.
Common situations: Shared repository commands surviving past a request-scoped transaction; error handlers that roll back and then continue processing; connection close/abort during async flows invalidating the pending transaction.
Related errors
- Turso database is closed.
- Transaction must be a TursoTransaction.
- Transaction must be a SqliteTransaction.
- The transaction connection does not match the command connec
- Execute requires the command to have a transaction when the
AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-08-20).
Data as JSON: /api/errors/8bd40cea97202f44.
Report an issue: GitHub.