InvalidOperationException "Enumerator was modified" is raised when rolling back sql transaction
Description
Environment
Activity
Alex Zaytsev July 12, 2018 at 1:35 AM
Moved here. Duplicates
Денис Подзюбан September 8, 2016 at 10:19 PM
GeanG July 7, 2014 at 8:39 AM
We've had a similar issue.
In our case this was related to how we fixed the problem that ASMX's don't call context_error in the HTTP Module (we did the TX management in the ASMX's), we ended up using the solution mentioned here:
Christoph Wienands November 7, 2013 at 6:55 PM
One more stack trace, this time from a transaction timeout:
Exception Info: System.InvalidOperationException
Stack:
at NHibernate.Util.SequencedHashMap+OrderedEnumerator.MoveNext()
at NHibernate.Engine.StatefulPersistenceContext.AfterTransactionCompletion()
at NHibernate.Impl.SessionImpl.AfterTransactionCompletion(Boolean, NHibernate.ITransaction)
at NHibernate.Transaction.AdoNetWithDistributedTransactionFactory+DistributedTransactionContext.System.Transactions.IEnlistmentNotification.Rollback(System.Transactions.Enlistment)
at System.Transactions.VolatileEnlistmentAborting.EnterState(System.Transactions.InternalEnlistment)
at System.Transactions.TransactionStateAborted.EnterState(System.Transactions.InternalTransaction)
at System.Transactions.EnlistableStates.Timeout(System.Transactions.InternalTransaction)
at System.Transactions.Bucket.TimeoutTransactions()
at System.Transactions.BucketSet.TimeoutTransactions()
at System.Transactions.TransactionTable.ThreadTimer(System.Object)
at System.Threading.ExecutionContext.runTryCode(System.Object)
at System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(TryCode, CleanupCode, System.Object)
at System.Threading.ExecutionContext.Run(System.Threading.ExecutionContext, System.Threading.ContextCallback, System.Object, Boolean)
at System.Threading._TimerCallback.PerformTimerCallback(System.Object)
Chad Lee January 15, 2013 at 6:37 PM
I was able to fix the specific issue we were having by adding some read/write locks around the collection that was throwing this exception.
https://github.com/ArchonInfoSys/nhibernate-core/commit/7e5471027e6d78a75ebc1b06f0aed50bfb108fc7
I don't think this is a valid fix - this is more of a workaround. It doesn't solve the underlying issue: namely, that the System.Transactions.TransactionCompleted event handler (see AdoNetWithDistributedTransactionFactory) runs on a different thread than the code that is using the ISession. I don't think the NH code is taking this into account, assuming it is all going to happen on the same thread.
This is kind of fantom bug. It happens very rarely. Failed test tries to call ISession.Query and ther rollebacks transaction. The stack trace:
System.InvalidOperationException: Enumerator was modified
at NHibernate.Util.SequencedHashMap.OrderedEnumerator.MoveNext() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Util\SequencedHashMap.cs:line 688
at NHibernate.Engine.StatefulPersistenceContext.AfterTransactionCompletion() in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Engine\StatefulPersistenceContext.cs:line 323
at NHibernate.Impl.SessionImpl.AfterTransactionCompletion(Boolean success, ITransaction tx) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Impl\SessionImpl.cs:line 398
at NHibernate.Transaction.AdoNetWithDistributedTransactionFactory.DistributedTransactionContext.System.Transactions.IEnlistmentNotification.Rollback(Enlistment enlistment) in d:\CSharp\NH\NH\nhibernate\src\NHibernate\Transaction\AdoNetWithDistributedTransactionFactory.cs:line 150
at System.Transactions.InternalEnlistment.System.Transactions.IEnlistmentNotificationInternal.Rollback(IPromotedEnlistment enlistment)
at System.Transactions.Oletx.OletxVolatileEnlistment.Rollback()
at System.Transactions.Oletx.OletxPhase0VolatileEnlistmentContainer.Aborted()
at System.Transactions.Oletx.OletxPhase0VolatileEnlistmentContainer.OutcomeFromTransaction(TransactionStatus outcome)
at System.Transactions.Oletx.OutcomeEnlistment.InvokeOutcomeFunction(TransactionStatus status)
at System.Transactions.Oletx.OletxTransactionManager.ShimNotificationCallback(Object state, Boolean timeout)
at System.Threading._ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(Object state, Boolean timedOut)