{"record":{"id":"259ce80413d1797b","repo":"tursodatabase/turso","slug":"parallel-transactions-are-not-supported","errorCode":null,"errorMessage":"Parallel transactions are not supported.","messagePattern":"Parallel transactions are not supported\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"bindings/dotnet/src/Turso.Data.Sqlite/SqliteConnection.cs","lineNumber":346,"sourceCode":"    {\n        ArgumentNullException.ThrowIfNull(connection);\n    }\n\n    public new virtual SqliteTransaction BeginTransaction()\n        => BeginTransaction(IsolationLevel.Unspecified);\n\n    public virtual SqliteTransaction BeginTransaction(bool deferred)\n        => BeginTransaction(IsolationLevel.Unspecified, deferred);\n\n    public new virtual SqliteTransaction BeginTransaction(IsolationLevel isolationLevel)\n        => BeginTransaction(isolationLevel, deferred: isolationLevel == IsolationLevel.ReadUncommitted);\n\n    public virtual SqliteTransaction BeginTransaction(IsolationLevel isolationLevel, bool deferred)\n    {\n        if (State != ConnectionState.Open)\n            throw new InvalidOperationException(Properties.Resources.CallRequiresOpenConnection(nameof(BeginTransaction)));\n        if (Transaction is not null)\n            throw new InvalidOperationException(Properties.Resources.ParallelTransactionsNotSupported);\n\n        Transaction = new SqliteTransaction(this, isolationLevel, deferred);\n        return Transaction;\n    }\n\n    public virtual void CreateCollation(string name, Comparison<string>? comparison)\n    {\n        RegisterCollation(name, comparison is null ? null : (left, right) => comparison(left, right));\n    }\n\n    public virtual void CreateCollation<T>(string name, T state, Func<T, string, string, int>? comparison)\n    {\n        RegisterCollation(name, comparison is null ? null : (left, right) => comparison(state, left, right));\n    }\n\n    public virtual void CreateFunction<TResult>(string name, Func<TResult>? function, bool isDeterministic = false)\n    {\n        RegisterScalarFunction(name, 0, isDeterministic, function is null ? null : _ => function());","sourceCodeStart":328,"sourceCodeEnd":364,"githubUrl":"https://github.com/tursodatabase/turso/blob/6c7252267988c76e632af00a671e4b9788dfae13/bindings/dotnet/src/Turso.Data.Sqlite/SqliteConnection.cs#L328-L364","documentation":"BeginTransaction throws InvalidOperationException when the connection already exposes a non-null Transaction, because SQLite permits only one active transaction per connection. There is no nested-transaction support and no automatic commit of the previous one; the second BeginTransaction is rejected outright. Note that disposing a SqliteTransaction rolls it back, so a transaction whose Dispose was skipped also keeps this guard tripped.","triggerScenarios":"Calling BeginTransaction twice without Commit/Rollback/Dispose in between; wrapping code that starts its own transaction inside an outer transactional block; helper methods that 'ensure a transaction' unconditionally; forgetting 'using' on the first transaction so it stays active after an exception.","commonSituations":"Unit-of-work patterns layered over repository methods that also transact, re-entrant service code, and error paths that skip transaction cleanup leaving Transaction set on a pooled/reused connection instance.","solutions":["Commit, roll back, or dispose the existing transaction before starting a new one ('await using' / 'using' on the SqliteTransaction guarantees this).","Pass the existing transaction down (set cmd.Transaction = conn.Transaction) instead of starting a second one; or use savepoints ('SAVEPOINT sp1') for nested semantics on SQLite 3.31+.","Restructure so exactly one layer owns transaction boundaries."],"exampleFix":"// before\nusing var conn = new SqliteConnection(cs);\nconn.Open();\nvar tx1 = conn.BeginTransaction();\nvar tx2 = conn.BeginTransaction(); // throws: Parallel transactions are not supported\n\n// after\nusing var conn = new SqliteConnection(cs);\nconn.Open();\nusing (var tx1 = conn.BeginTransaction())\n{\n    // do work; reuse tx1 on all commands, or nest with savepoints:\n    conn.ExecuteNonQuery(\"SAVEPOINT sp1\");\n    // ...\n    conn.ExecuteNonQuery(\"RELEASE sp1\");\n}","handlingStrategy":"validation","validationCode":"static SqliteTransaction? ExistingOrNew(SqliteConnection conn)\n    => conn.Transaction ?? conn.BeginTransaction();\n\n// always scope transactions so Dispose rolls back on error:\n// using var tx = conn.BeginTransaction();","typeGuard":null,"tryCatchPattern":"null","preventionTips":["Always create transactions with 'using' so exceptions cannot leave them active.","Keep transaction ownership in one layer; pass conn.Transaction to commands instead of opening a second one.","Use SAVEPOINT/RELEASE for nesting semantics on a single connection."],"tags":["ado-net","sqlite","turso","transactions"],"backgroundTag":"nested-transaction","analyzedSha":"6c7252267988c76e632af00a671e4b9788dfae13","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}