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
- Verify the LiteDB version under test still enforces that ReleaseTransaction rejects calls from threads that do not own the transaction.
- Inspect the host log lines emitted by the worker: 'ReleaseTransaction completed without throwing' confirms the guard did not fire.
- Re-check the reflection setup: ensure capturedTransaction is the live, main-thread-owned transaction when the worker invokes ReleaseTransaction.
- 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
- Log both outcomes (threw vs completed) so a missing guard is observable, not just a hard failure.
- Pin the LiteDB version the repro asserts against so message/behavior drift is detected at upgrade time.
- Treat a non-throwing ReleaseTransaction as inconclusive in CI rather than a red failure unless the guard is required.
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
- Timed out waiting for ReleaseTransaction to finish.
- LiteException did not contain expected message. Actual: {obs
- Failed to begin primary transaction for reproduction.
- MAPPING_ERROR
- ENTITY_INITIALIZATION_FAILED
AI-assisted analysis of litedb-org/LiteDB@f906a5f850 (2026-08-13).
Data as JSON: /api/errors/a2d38b4319b59931.
Report an issue: GitHub.