{"record":{"id":"8bd40cea97202f44","repo":"tursodatabase/turso","slug":"the-transaction-has-completed","errorCode":null,"errorMessage":"The transaction has completed.","messagePattern":"The transaction has completed\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"bindings/dotnet/src/Turso.Data.Sqlite/SqliteCommand.cs","lineNumber":597,"sourceCode":"            throw new InvalidOperationException(Properties.Resources.SetRequiresNoOpenReader(property));\n    }\n\n    private void EnsureExecutable(string method)\n    {\n        if (_hasOpenReader)\n            throw new InvalidOperationException(Properties.Resources.DataReaderOpen);\n        if (Connection is null || Connection.State != ConnectionState.Open)\n            throw new InvalidOperationException(Properties.Resources.CallRequiresOpenConnection(method));\n        if (Transaction is { IsCompleted: true } or { WasRolledBackExternally: true })\n            throw new InvalidOperationException(Properties.Resources.TransactionCompleted);\n        if (Transaction is not null && !ReferenceEquals(Transaction.Connection, Connection))\n            throw new InvalidOperationException(Properties.Resources.TransactionConnectionMismatch);\n\n        var connectionTransaction = Connection.Transaction;\n        if (connectionTransaction is null || ReferenceEquals(Transaction, connectionTransaction))\n            return;\n        if (connectionTransaction.IsCompleted)\n            throw new InvalidOperationException(Properties.Resources.TransactionCompleted);\n        if (!IsTransactionControlCommand(CommandText))\n            throw new InvalidOperationException(Properties.Resources.TransactionRequired);\n    }\n\n    private void CloseReader()\n    {\n        _hasOpenReader = false;\n        Connection?.ReaderClosed();\n    }\n\n    internal Action OwnBufferedReader()\n    {\n        _hasOpenReader = true;\n        Connection?.ReaderOpened();\n        return () =>\n        {\n            CloseReader();\n            Dispose();","sourceCodeStart":579,"sourceCodeEnd":615,"githubUrl":"https://github.com/tursodatabase/turso/blob/6c7252267988c76e632af00a671e4b9788dfae13/bindings/dotnet/src/Turso.Data.Sqlite/SqliteCommand.cs#L579-L615","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ntx.Commit();\ncmd.ExecuteNonQuery(); // cmd still bound to the completed transaction -> throws\n\n// after\ntx.Commit();\nusing var tx2 = conn.BeginTransaction();\ncmd.Transaction = tx2;\ncmd.ExecuteNonQuery();","handlingStrategy":"validation","validationCode":"// completion is observable via the thrown error; track it locally instead\nsealed class TxScope(SqliteConnection conn) {\n    SqliteTransaction? tx;\n    public bool Active => tx is not null;\n    public SqliteTransaction Begin() => tx = conn.BeginTransaction();\n    public void Finish() { if (tx is not null) { tx.Dispose(); tx = null; } }\n}\n\nif (scope.Active) cmd.ExecuteNonQuery();","typeGuard":null,"tryCatchPattern":"catch (InvalidOperationException) when (transactionWasFinished) {\n    using var tx2 = conn.BeginTransaction();\n    cmd.Transaction = tx2;\n    cmd.ExecuteNonQuery();\n}","preventionTips":["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."],"tags":["dotnet","ado-net","transaction","lifecycle"],"backgroundTag":"transaction-completed","analyzedSha":"6c7252267988c76e632af00a671e4b9788dfae13","analyzedAt":"2026-08-20T07:02:18.389Z","contentChangedAt":"2026-08-20T07:02:18.389Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}