tursodatabase/turso · error · SqliteException
SqliteCommand.ToSqliteException(ex)
Error message
SqliteCommand.ToSqliteException(ex)
What it means
The SqliteTransaction constructor asks the managed connection to BEGIN a transaction (BEGIN IMMEDIATE for serializable non-deferred transactions, otherwise BEGIN). If the backend rejects the BEGIN (e.g. a transaction is already active or the connection failed), the TursoException is converted to a SqliteException. The deferred fallback path uses plain text 'BEGIN;' via Execute.
Source
Thrown at bindings/dotnet/src/Turso.Data.Sqlite/SqliteTransaction.cs:33
{
_connection = connection;
_isolationLevel = NormalizeIsolationLevel(connection, isolationLevel, deferred);
if (_isolationLevel == IsolationLevel.ReadUncommitted)
connection.ReadUncommitted = true;
if (connection.IsManagedConnection)
{
try
{
_managedTransaction = new global::Turso.TursoTransaction(
connection.ManagedConnection,
_isolationLevel,
deferred);
}
catch (Turso.Raw.Public.TursoException ex)
{
throw SqliteCommand.ToSqliteException(ex);
}
return;
}
Execute(_isolationLevel == IsolationLevel.Serializable && !deferred ? "BEGIN IMMEDIATE;" : "BEGIN;");
}
public override IsolationLevel IsolationLevel => _isolationLevel;
public override bool SupportsSavepoints => true;
protected override DbConnection? DbConnection => Connection;
public new virtual SqliteConnection? Connection => _connection;
internal bool IsCompleted => _completed;
View on GitHub (pinned to 6c72522679)
Solutions
- Ensure the previous SqliteTransaction is committed, rolled back, or disposed before starting a new one on the same connection.
- Use one transaction at a time per connection; don't share a SqliteConnection across threads without synchronization.
- Catch SqliteException and check for SQLITE_BUSY (5) to implement retry/backoff on locked databases.
- If available, enable connection pooling per logical operation instead of manual nested transactions.
Example fix
// before
var tx = conn.BeginTransaction();
var tx2 = conn.BeginTransaction(); // throws: transaction already active
// after
using (var tx = conn.BeginTransaction())
{
// ...
tx.Commit();
} // dispose ends the transaction before another can begin Defensive patterns
Strategy: try-catch
Validate before calling
// ensure no transaction is active before beginning a new one
if (conn.EnlistedTransaction != null || _currentTx != null)
throw new InvalidOperationException("transaction already active on this connection"); Type guard
static bool CanBeginTransaction(SqliteConnection conn) => conn.State == ConnectionState.Open;
Try / catch
try
{
using var tx = conn.BeginTransaction(IsolationLevel.ReadCommitted);
// ... work, tx.Commit()
}
catch (SqliteException ex) when (ex.SqliteErrorCode == 5)
{
// SQLITE_BUSY: retry with backoff
}
catch (SqliteException ex)
{
logger.LogError(ex, "BEGIN failed");
throw;
} Prevention
- Never nest BeginTransaction on one connection
- Always use 'using' so transactions end deterministically
- Don't share a SqliteConnection across concurrent tasks
- Retry BEGIN IMMEDIATE with backoff when the database is busy
When it happens
Trigger: calling conn.BeginTransaction() while another transaction is already open on the same connection; connection to remote Turso server is broken; backend rejects BEGIN IMMEDIATE because the database is locked.
Common situations: Nested transaction attempts (BeginTransaction inside a using-block whose transaction wasn't committed/disposed), parallel use of one connection from multiple threads, busy database under contention.
Understand the failure class
Background: "query failed", "%w: SQL error" — wrapped database query errors in Go libraries explained — this error's family across 3 libraries.
Related errors
- Transaction must be a TursoTransaction.
- Transaction must be a SqliteTransaction.
- Command type {commandType} is not supported.
- The transaction connection does not match the command connec
- The transaction has completed.
AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-09-06).
Data as JSON: /api/errors/4e960259faaeb560.
Report an issue: GitHub.