litedb-org/LiteDB · error · InvalidOperationException

Failed to begin primary transaction for reproduction.

Error message

Failed to begin primary transaction for reproduction.

What it means

Thrown by the Issue 2586 repro harness when db.BeginTrans() returned false on the primary thread. LiteDB's BeginTrans returns false (rather than throwing) when the calling thread already has an active transaction, so the repro treats that as a fatal setup failure because it needs a fresh primary transaction to drive the rollback path.

Source

Thrown at LiteDB.ReproRunner/Repros/Issue_2586_RollbackTransaction/Program.cs:180

            try
            {
                db.Rollback();
            }
            catch (LiteException ex)
            {
                Log(host, $"[{threadId}] Holder rollback threw: {ex.Message}", ReproHostLogLevel.Warning);
            }
        }
    }

    private static bool RunFailingTransaction(ReproHostClient host, LiteDatabase db, ILiteCollection<LargeDocument> collection)
    {
        Console.WriteLine();
        Log(host, $"Starting write transaction on thread {Thread.CurrentThread.ManagedThreadId}.");

        if (!db.BeginTrans())
        {
            throw new InvalidOperationException("Failed to begin primary transaction for reproduction.");
        }

        TransactionInspector? inspector = null;
        var maxSize = 0;
        var safepointTriggered = false;
        var shouldTriggerSafepoint = false;

        var payloadA = new string('A', 4_096);
        var payloadB = new string('B', 4_096);
        var payloadC = new string('C', 2_048);
        var largeBinary = new byte[128 * 1024];

        try
        {
            for (var i = 0; i < DocumentWriteCount; i++)
            {
                if (shouldTriggerSafepoint && !safepointTriggered)
                {

View on GitHub (pinned to f906a5f850)

Solutions

  1. Ensure the primary thread has no open transaction: call db.Rollback() or db.Commit() (or dispose the LiteDatabase) before reaching RunFailingTransaction.
  2. Use a fresh LiteDatabase instance for the primary write transaction so no ambient transaction is inherited.
  3. Wrap the earlier transaction in try/finally so an exception always releases it.
  4. Log whether BeginTrans returned false versus threw, to distinguish 'already in transaction' from a deeper engine error.

Example fix

// before
if (!db.BeginTrans())
{
    throw new InvalidOperationException("Failed to begin primary transaction for reproduction.");
}

// after
// release any ambient transaction left from setup
try { db.Rollback(); } catch { /* no active transaction */ }
if (!db.BeginTrans())
{
    throw new InvalidOperationException("Failed to begin primary transaction for reproduction (thread already in a transaction?).");
}
Defensive patterns

Strategy: validation

Validate before calling

// Ensure no ambient transaction before starting the primary one
try { db.Rollback(); }
catch (LiteException) { /* no active transaction; expected */ }
if (!db.BeginTrans())
{
    throw new InvalidOperationException("Thread already in a transaction; cannot start primary reproduction transaction.");
}

Prevention

When it happens

Trigger: Calling db.BeginTrans() on a thread that already began a transaction earlier and never committed/rolled it back; or reusing a LiteDatabase/LiteEngine whose ambient transaction was left open by a prior step of the repro. The 'primary transaction for reproduction' must be the first transaction on that thread.

Common situations: Repro/test code that begins a transaction in a setup phase and forgets to commit or roll back before the main phase; shared LiteDatabase instances across test methods without teardown; an earlier exception that skipped the Rollback call in a finally block.

Related errors


AI-assisted analysis of litedb-org/LiteDB@f906a5f850 (2026-08-13). Data as JSON: /api/errors/1996c0d5f3632cb0. Report an issue: GitHub.