{"record":{"id":"a2bd6ce12749974f","repo":"tursodatabase/turso","slug":"a-transaction-is-already-active-on-this-connection","errorCode":null,"errorMessage":"A transaction is already active on this connection.","messagePattern":"A transaction is already active on this connection\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"bindings/dotnet/src/Turso.Data/TursoConnection.cs","lineNumber":351,"sourceCode":"                if (_remoteTransactionActive)\n                    InvalidateRemoteSession();\n                else\n                    remoteClient.ResetSession();\n            }\n            throw;\n        }\n        catch\n        {\n            InvalidateRemoteSession();\n            throw;\n        }\n    }\n\n    internal void BeginRemoteTransaction(IsolationLevel isolationLevel, bool deferred = true)\n    {\n        var remoteClient = _remoteClient ?? throw new InvalidOperationException(\"Turso database is closed.\");\n        if (_remoteTransactionActive)\n            throw new InvalidOperationException(\"A transaction is already active on this connection.\");\n\n        _remoteTransactionFailure = null;\n        _remoteTransactionActive = true;\n        try\n        {\n            remoteClient\n                .ExecuteAsync(\n                    isolationLevel == IsolationLevel.Serializable && !deferred\n                        ? \"BEGIN IMMEDIATE\"\n                        : \"BEGIN\",\n                    new TursoParameterCollection(),\n                    wantRows: false,\n                    DefaultTimeout,\n                    closeAfter: false,\n                    CancellationToken.None)\n                .GetAwaiter()\n                .GetResult();\n        }","sourceCodeStart":333,"sourceCodeEnd":369,"githubUrl":"https://github.com/tursodatabase/turso/blob/6c7252267988c76e632af00a671e4b9788dfae13/bindings/dotnet/src/Turso.Data/TursoConnection.cs#L333-L369","documentation":"BeginRemoteTransaction tracks one _remoteTransactionActive flag per connection and refuses a second BEGIN with 'A transaction is already active on this connection.' The remote path supports at most one outstanding transaction per connection: no nested transactions and no concurrent ones on a shared connection.","triggerScenarios":"Calling connection.BeginTransaction() twice without Commit/Rollback in between; two threads or requests sharing one connection each calling BeginTransaction; repository methods that each wrap their work in a transaction and call each other.","commonSituations":"Recursive service methods with [Transactional]-style wrappers; a pooled connection reused by concurrent requests that both begin transactions; a missing commit in an error path leaving the transaction open.","solutions":["Commit or Rollback the existing TursoTransaction before beginning another on the same connection","Use one connection per concurrent transaction; never share a TursoConnection across threads for transactional work","Restructure nested 'transactional' methods to accept an optional existing transaction instead of always opening a new one"],"exampleFix":"// before\nvar tx1 = conn.BeginTransaction();\nvar tx2 = conn.BeginTransaction(); // throws: already active\n\n// after\nusing (var tx = conn.BeginTransaction())\n{\n    // all work, including nested helper calls, joins tx\n    tx.Commit();\n}","handlingStrategy":"validation","validationCode":"// one transaction per connection at a time -- serialize access\nawait _connectionGate.WaitAsync();\ntry\n{\n    using var tx = conn.BeginTransaction();\n    /* work */ tx.Commit();\n}\nfinally { _connectionGate.Release(); }","typeGuard":"static bool SupportsNestedTransactions => false;","tryCatchPattern":"try { var tx = conn.BeginTransaction(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"already active\"))\n{\n    // commit/rollback the existing transaction first, or use a separate connection\n}","preventionTips":["Commit or Rollback before beginning another transaction on the same connection","Never share one connection between concurrent transactions","Pass an optional ambient transaction into nested methods instead of opening a new one"],"tags":["csharp","dotnet","turso","transactions","concurrency"],"backgroundTag":"transaction-already-active","analyzedSha":"6c7252267988c76e632af00a671e4b9788dfae13","analyzedAt":"2026-09-06T07:15:26.990Z","contentChangedAt":"2026-09-06T07:15:26.990Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}