tursodatabase/turso · error · NotSupportedException

Isolation level {isolationLevel} is not supported.

Error message

Isolation level {isolationLevel} is not supported.

What it means

TursoTransaction.NormalizeIsolationLevel maps several System.Transactions IsolationLevel values onto what SQLite/Turso actually supports. Most levels are coerced to Serializable, ReadUncommitted is allowed, and anything else (e.g. Chaos, Snapshot) has no mapping, so NotSupportedException is thrown.

Source

Thrown at bindings/dotnet/src/Turso.Data/TursoTransaction.cs:144

        _completed = true;
    }

    private void ThrowIfCompleted()
    {
        if (_completed)
            throw new InvalidOperationException("This transaction has already completed.");
    }

    private static IsolationLevel NormalizeIsolationLevel(IsolationLevel isolationLevel)
    {
        return isolationLevel switch
        {
            IsolationLevel.Unspecified => IsolationLevel.Serializable,
            IsolationLevel.Serializable => IsolationLevel.Serializable,
            IsolationLevel.ReadCommitted => IsolationLevel.Serializable,
            IsolationLevel.RepeatableRead => IsolationLevel.Serializable,
            IsolationLevel.ReadUncommitted => IsolationLevel.ReadUncommitted,
            _ => throw new NotSupportedException($"Isolation level {isolationLevel} is not supported.")
        };
    }
}

View on GitHub (pinned to 6c72522679)

Solutions

  1. Use IsolationLevel.Serializable (the default and fully supported) or ReadUncommitted.
  2. Remove Snapshot/Chaos settings from TransactionScope or connection BeginTransaction calls.
  3. Wrap the BeginTransaction call in a mapping function that converts unsupported levels to Serializable before calling the provider.
  4. If you truly need Snapshot semantics, restructure the workload to rely on explicit transactions instead.

Example fix

// before
using var tx = conn.BeginTransaction(IsolationLevel.Snapshot);

// after
var level = iso == IsolationLevel.Snapshot ? IsolationLevel.Serializable : iso;
using var tx = conn.BeginTransaction(level);
Defensive patterns

Strategy: validation

Validate before calling

// Map any unsupported level before calling the provider
IsolationLevel Normalize(IsolationLevel iso) =>
    iso is IsolationLevel.Serializable or IsolationLevel.ReadCommitted or
          IsolationLevel.RepeatableRead or IsolationLevel.Unspecified
        ? IsolationLevel.Serializable
        : iso == IsolationLevel.ReadUncommitted ? IsolationLevel.ReadUncommitted
        : throw new NotSupportedException($"{iso} not supported by Turso");

Try / catch

try { tx = conn.BeginTransaction(iso); }
catch (NotSupportedException ex) when (ex.Message.Contains("Isolation level"))
{
    tx = conn.BeginTransaction(IsolationLevel.Serializable); // safe fallback
}

Prevention

When it happens

Trigger: Beginning a TursoTransaction with BeginTransaction(IsolationLevel.Chaos) or IsolationLevel.Snapshot, or setting an unsupported level via System.Transactions.TransactionScope options that propagate into the ADO.NET provider.

Common situations: Porting code written for SQL Server that uses Snapshot isolation; TransactionScope configured with a non-SQLite isolation level; generic ORM code that passes through a configurable isolation level enum.

Related errors


AI-assisted analysis of tursodatabase/turso@6c72522679 (2026-09-06). Data as JSON: /api/errors/479d1a9cc3fd7a5b. Report an issue: GitHub.