tursodatabase/turso · error · ArgumentException

Transaction must be a SqliteTransaction.

Error message

Transaction must be a SqliteTransaction.

What it means

SqliteCommand implements DbCommand, whose constructor accepts any DbTransaction; the provider understands only SqliteTransaction (its own type that talks to the native engine), so a non-null transaction of another ADO.NET provider is rejected with ArgumentException. Null is allowed and means 'not enlisted'. The check happens at construction so the failure surfaces before execution inside native code.

Source

Thrown at bindings/dotnet/src/Turso.Data.Sqlite/SqliteCommand.cs:52

    }

    public SqliteCommand(string? commandText, SqliteConnection? connection)
        : this(commandText)
    {
        Connection = connection;
    }

    public SqliteCommand(string? commandText, SqliteConnection? connection, SqliteTransaction? transaction)
        : this(commandText, connection)
    {
        Transaction = transaction;
    }

    public SqliteCommand(string? commandText, SqliteConnection? connection, DbTransaction? transaction)
        : this(commandText, connection)
    {
        Transaction = transaction as SqliteTransaction
                      ?? (transaction is null ? null : throw new ArgumentException("Transaction must be a SqliteTransaction.", nameof(transaction)));
    }

    [AllowNull]
    public override string CommandText
    {
        get => _commandText;
        set
        {
            ThrowIfReaderOpen(nameof(CommandText));
            _commandText = value ?? string.Empty;
        }
    }

    public override int CommandTimeout
    {
        get => _commandTimeout;
        set
        {

View on GitHub (pinned to 6c72522679)

Solutions

  1. Pass the SqliteTransaction returned by sqliteConn.BeginTransaction().
  2. Pattern-match before passing: only forward transactions that are SqliteTransaction.
  3. In generic helpers, keep connection+transaction provider pairs together (DbProviderFactory) so the right types flow.

Example fix

// before
DbTransaction tx = GetUnitOfWorkTransaction();   // e.g. a SqlTransaction from SQL Server
using var cmd = new SqliteCommand(sql, conn, tx); // throws: must be a SqliteTransaction

// after
using var tx = conn.BeginTransaction();           // SqliteTransaction from the same connection
using var cmd = new SqliteCommand(sql, conn, tx);
Defensive patterns

Strategy: type-guard

Validate before calling

if (transaction is not null and not SqliteTransaction)
    throw new ArgumentException("Transaction must come from a SqliteConnection.");

var cmd = new SqliteCommand(sql, conn, transaction as SqliteTransaction);

Type guard

static SqliteTransaction? AsSqlite(DbTransaction? tx) => tx switch {
    null => null,
    SqliteTransaction s => s,
    _ => throw new ArgumentException("Transaction must be a SqliteTransaction.")
};

Prevention

When it happens

Trigger: new SqliteCommand(sql, conn, tx) where tx came from another provider (e.g., SqlTransaction) or from a different connection; generic ADO.NET helpers that thread DbTransaction through to any command; DI wiring that injects the wrong DbTransaction.

Common situations: Multi-database unit-of-work code passing one provider's transaction to another's command; copy-paste from System.Data.SqlClient samples; provider-agnostic data layers that lost type pairing.

Related errors


AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-08-20). Data as JSON: /api/errors/6751624d6e97970d. Report an issue: GitHub.