tursodatabase/turso · error · InvalidOperationException
{method} requires an open connection.
Error message
{method} requires an open connection. What it means
BeginTransaction checks State before doing anything and throws InvalidOperationException when the connection is not Open. Unlike some providers that open implicitly, this one requires an explicit Open() first; transactions cannot start against a closed connection because they need a live native database handle. The same CallRequiresOpenConnection guard covers other APIs (BackupDatabase, and the internal DatabaseHandle/EnsureOpen used by command execution).
Source
Thrown at bindings/dotnet/src/Turso.Data.Sqlite/SqliteConnection.cs:344
public static void ClearPool(SqliteConnection connection)
{
ArgumentNullException.ThrowIfNull(connection);
}
public new virtual SqliteTransaction BeginTransaction()
=> BeginTransaction(IsolationLevel.Unspecified);
public virtual SqliteTransaction BeginTransaction(bool deferred)
=> BeginTransaction(IsolationLevel.Unspecified, deferred);
public new virtual SqliteTransaction BeginTransaction(IsolationLevel isolationLevel)
=> BeginTransaction(isolationLevel, deferred: isolationLevel == IsolationLevel.ReadUncommitted);
public virtual SqliteTransaction BeginTransaction(IsolationLevel isolationLevel, bool deferred)
{
if (State != ConnectionState.Open)
throw new InvalidOperationException(Properties.Resources.CallRequiresOpenConnection(nameof(BeginTransaction)));
if (Transaction is not null)
throw new InvalidOperationException(Properties.Resources.ParallelTransactionsNotSupported);
Transaction = new SqliteTransaction(this, isolationLevel, deferred);
return Transaction;
}
public virtual void CreateCollation(string name, Comparison<string>? comparison)
{
RegisterCollation(name, comparison is null ? null : (left, right) => comparison(left, right));
}
public virtual void CreateCollation<T>(string name, T state, Func<T, string, string, int>? comparison)
{
RegisterCollation(name, comparison is null ? null : (left, right) => comparison(state, left, right));
}
public virtual void CreateFunction<TResult>(string name, Func<TResult>? function, bool isDeterministic = false)View on GitHub (pinned to 6c72522679)
Solutions
- Call conn.Open() before conn.BeginTransaction().
- Centralize the check in an EnsureOpen helper: 'if (conn.State != ConnectionState.Open) conn.Open();'.
- Verify in debuggers/logs that the same connection instance you transact on is the one that was opened (not a copy or a different field).
Example fix
// before using var conn = new SqliteConnection(cs); using var tx = conn.BeginTransaction(); // throws: requires an open connection // after using var conn = new SqliteConnection(cs); conn.Open(); using var tx = conn.BeginTransaction();
Defensive patterns
Strategy: validation
Validate before calling
static SqliteTransaction BeginTransactionSafe(SqliteConnection conn)
{
if (conn.State != ConnectionState.Open)
conn.Open();
return conn.BeginTransaction();
} Prevention
- Establish the invariant 'open once, at the composition root' for each connection.
- Check State in test fixtures before starting transactions.
- Static analysis: flag BeginTransaction calls on connections not obviously preceded by Open.
When it happens
Trigger: 'var conn = new SqliteConnection(cs); var tx = conn.BeginTransaction();' with no Open() in between; BeginTransaction in a unit test whose fixture opens the connection asynchronously and races; helpers that assume lazy connection opening; calling BeginTransaction after Close() on a reused connection object.
Common situations: Ported from providers with implicit open (EF Core patterns usually open for you, raw ADO.NET does not), connection lifecycle split across methods where Open happens later than expected, and mock-heavy tests that never exercise the real open path.
Related errors
- Parallel transactions are not supported.
- 5
- The connection string can only be set when the connection is
- The connection is already open.
- Changing databases is not supported.
AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-08-20).
Data as JSON: /api/errors/59f7088bdf7a2a26.
Report an issue: GitHub.