litedb-org/LiteDB · error · InvalidOperationException

Expected LiteException was not observed.

Error message

Expected LiteException was not observed.

What it means

Thrown by the Issue 2561 repro harness when the worker thread finished without capturing a LiteException. The repro asserts that calling ReleaseTransaction on a transaction owned by another thread must throw LiteException; if ReleaseTransaction completed silently, observedException stays null and this assertion fires. It signals that the expected thread-affinity guard did not trigger.

Source

Thrown at LiteDB.ReproRunner/Repros/Issue_2561_TransactionMonitor/Program.cs:144

            }
        })
        {
            IsBackground = true,
            Name = "Issue2561-Repro-Worker"
        };

        worker.Start();

        if (!reproObserved.Wait(TimeSpan.FromSeconds(10)))
        {
            throw new TimeoutException("Timed out waiting for ReleaseTransaction to finish.");
        }

        rollback.Invoke(engine, Array.Empty<object>());

        if (observedException is null)
        {
            throw new InvalidOperationException("Expected LiteException was not observed.");
        }

        if (!observedException.Message.Contains("current thread must contains transaction parameter", StringComparison.OrdinalIgnoreCase))
        {
            throw new InvalidOperationException($"LiteException did not contain expected message. Actual: {observedException.Message}");
        }

        Log(host, "Repro succeeded: ReleaseTransaction threw on the wrong thread.");
    }

    private static void Log(ReproHostClient host, string message, ReproHostLogLevel level = ReproHostLogLevel.Information)
    {
        host.SendLog(message, level);

        if (level >= ReproHostLogLevel.Warning)
        {
            Console.Error.WriteLine(message);
        }

View on GitHub (pinned to f906a5f850)

Solutions

  1. Verify the LiteDB version under test still enforces that ReleaseTransaction rejects calls from threads that do not own the transaction.
  2. Inspect the host log lines emitted by the worker: 'ReleaseTransaction completed without throwing' confirms the guard did not fire.
  3. Re-check the reflection setup: ensure capturedTransaction is the live, main-thread-owned transaction when the worker invokes ReleaseTransaction.
  4. If the guard was intentionally removed, retire this repro rather than treating the assertion as a failure.
Defensive patterns

Strategy: validation

Validate before calling

// Before asserting, confirm the worker captured something
if (observedException is null)
{
    Log(host, "ReleaseTransaction did not throw; thread-affinity guard may be absent in this build.", ReproHostLogLevel.Warning);
    return; // mark repro inconclusive instead of throwing

Prevention

When it happens

Trigger: ReleaseTransaction.Invoke(monitor, capturedTransaction) returned normally on the worker thread instead of throwing, meaning the monitor allowed a foreign thread to release a transaction it did not open. Occurs on LiteDB builds where the thread-affinity check in ReleaseTransaction was removed, weakened, or short-circuited.

Common situations: Running the repro against a LiteDB version that already fixed or regressed the thread-affinity guard, or where the captured transaction object is no longer the active one by the time the worker runs (so ReleaseTransaction is a no-op rather than a violation).

Related errors


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