{"record":{"id":"9d43d973a7b318d9","repo":"tursodatabase/turso","slug":"transaction-control-sql-is-not-supported-on-a-mana","errorCode":null,"errorMessage":"Transaction-control SQL is not supported on a managed SqliteConnection. Use SqliteConnection.BeginTransaction and SqliteTransaction instead.","messagePattern":"Transaction-control SQL is not supported on a managed SqliteConnection\\. Use SqliteConnection\\.BeginTransaction and SqliteTransaction instead\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"bindings/dotnet/src/Turso.Data.Sqlite/SqliteCommand.cs","lineNumber":483,"sourceCode":"\n        try\n        {\n            AddManagedParameters(command, statement);\n            return command;\n        }\n        catch\n        {\n            command.Dispose();\n            throw;\n        }\n    }\n\n    private IReadOnlyList<ManagedSqliteStatement> GetManagedStatements()\n    {\n        var statements = ManagedSqliteStatementParser.Parse(CommandText);\n        if (statements.Any(statement => statement.IsTransactionControl && !CanExecuteSavepointStatement(statement)))\n        {\n            throw new InvalidOperationException(\n                \"Transaction-control SQL is not supported on a managed SqliteConnection. \"\n                + \"Use SqliteConnection.BeginTransaction and SqliteTransaction instead.\");\n        }\n\n        if (statements.Count > 1\n            && Connection!.IsDirectRemote\n            && !Connection.ManagedReadYourWrites\n            && Transaction is null)\n        {\n            throw new NotSupportedException(\n                \"Multi-statement SqliteCommand execution requires Read Your Writes=True \"\n                + \"or an explicit SqliteTransaction on a direct remote connection.\");\n        }\n\n        return statements;\n    }\n\n    private bool CanExecuteSavepointStatement(ManagedSqliteStatement statement)","sourceCodeStart":465,"sourceCodeEnd":501,"githubUrl":"https://github.com/tursodatabase/turso/blob/6c7252267988c76e632af00a671e4b9788dfae13/bindings/dotnet/src/Turso.Data.Sqlite/SqliteCommand.cs#L465-L501","documentation":"GetManagedStatements rejects SQL containing transaction-control statements (BEGIN/COMMIT/ROLLBACK/SAVEPOINT etc.) executed as raw command text on a managed SqliteConnection, unless the statement is an allowed savepoint via CanExecuteSavepointStatement. Transactions must be managed through the ADO.NET API (BeginTransaction/SqliteTransaction) so the facade can track transaction state.","triggerScenarios":"Executing CommandText = \"BEGIN\" / \"COMMIT\" / \"ROLLBACK\" (or disallowed SAVEPOINT/RELEASE forms) via ExecuteNonQuery on a SqliteCommand over a managed connection.","commonSituations":"Porting code from raw sqlite3 APIs or other drivers where explicit BEGIN/COMMIT SQL is the norm; script files run verbatim containing transaction statements; dynamically generated SQL that prepends BEGIN.","solutions":["Remove BEGIN/COMMIT/ROLLBACK from CommandText and use connection.BeginTransaction() with tx.Commit()/tx.Rollback() instead","If savepoints are needed, use the savepoint forms permitted by CanExecuteSavepointStatement within a SqliteTransaction","Split script files so transaction-control lines are handled by the API, not passed as SQL text"],"exampleFix":"// before\nconn.Execute(\"BEGIN\");\nconn.Execute(\"INSERT INTO t VALUES (1)\");\nconn.Execute(\"COMMIT\");\n// after\nusing var tx = conn.BeginTransaction();\nconn.Execute(\"INSERT INTO t VALUES (1)\", transaction: tx);\ntx.Commit();","handlingStrategy":"validation","validationCode":"var ctl = new[]{\"BEGIN\",\"COMMIT\",\"ROLLBACK\",\"SAVEPOINT\",\"RELEASE\",\"END\"};\nif (commandText.Split(';').Any(s => ctl.Contains(s.Trim().Split(' ')[0], StringComparer.OrdinalIgnoreCase)))\n    throw new InvalidOperationException(\"Use SqliteTransaction instead of transaction-control SQL.\");","typeGuard":null,"tryCatchPattern":"try { cmd.ExecuteNonQuery(); }\ncatch (InvalidOperationException ex) when (ex.Message.Contains(\"Transaction-control SQL\"))\n{\n    using var tx = connection.BeginTransaction();\n    cmd.Transaction = tx;\n    cmd.ExecuteNonQuery();\n    tx.Commit();\n}","preventionTips":["Strip BEGIN/COMMIT/ROLLBACK from SQL scripts before feeding them to SqliteCommand","Use BeginTransaction/SqliteTransaction for all transaction management","Handle savepoints through SqliteTransaction APIs rather than raw SAVEPOINT SQL"],"tags":["dotnet","transaction","unsupported-sql"],"backgroundTag":"unsupported-operation","analyzedSha":"6c7252267988c76e632af00a671e4b9788dfae13","analyzedAt":"2026-09-06T07:15:26.990Z","contentChangedAt":"2026-09-06T07:15:26.990Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}