Accounts can get into an error state where they can no longer log in

Bug manifested as a 500 error upon entering two-step code during auth. Other users were able to log in fine. Restart did not correct the issue.

Entries from the `two_step_session` table (stripped + anonymized):

    +----+---------+---------------------+--------------------+--------------------------------------+
    | id | version | expiry              | managed_subject_id | value                                |
    +----+---------+---------------------+--------------------+--------------------------------------+
    | 12 |       0 | 2014-01-21 23:49:39 |           99999999 | nyTtTFMZFZZKz0YZ...X9RSW7H5s59QdfPyZ |
    | 15 |       0 | 2014-01-21 23:50:21 |           99999999 | 9iMryiGgOJ3wU2eb...xKQftdKzHAU656VOJ |
    | 24 |       0 | 2014-01-22 00:09:53 |           99999999 | kZs1ToRB9p9wjVOE...emc6STdAXUFkhKZaX |
    | 30 |       0 | 2014-02-09 22:32:40 |           99999999 | hxKGKmkBVecKArsv...iQ5LWrRv2I6honHP3 |
    | 33 |       0 | 2014-02-11 05:13:59 |           99999999 | VTaYcTfCiiTaqhYq...ykMwcoszJPS0FXVey |
    +----+---------+---------------------+--------------------+--------------------------------------+

This occurred on the morning of 2014-04-22, which coincides with the expiry of three entries here.

Attempting to log in caused the following exception:

    [ 22.04.14 11:47:44.780] ERROR StackTrace  - Full Stack Trace:
    org.hibernate.ObjectDeletedException: deleted object would be re-saved by cascade (remove deleted object from associations): [aaf.vhr.TwoStepSession#15]
            at org.hibernate.impl.SessionImpl.forceFlush(SessionImpl.java:1230)
            at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:188)
            at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:117)
            at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
            at org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor.onSaveOrUpdate(ClosureEventTriggeringInterceptor.java:108)
            at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:685)
            at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:677)
            at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.java:252)
            at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:392)
            at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:335)
            at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
            at org.hibernate.engine.Cascade.cascadeCollectionElements(Cascade.java:425)
            at org.hibernate.engine.Cascade.cascadeCollection(Cascade.java:362)
            at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:338)
            at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:204)
            at org.hibernate.engine.Cascade.cascade(Cascade.java:161)
            at org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:154)
            at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:145)
            at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:88)
            at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
            at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216)
            at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383)
            at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133)
            at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)
            at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
            at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
            at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:387)
            at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
            at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
            at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
            at aaf.vhr.LoginService$$EnhancerByCGLIB$$fc5394c1.twoStepLogin(<generated>)
            at aaf.vhr.LoginService$twoStepLogin.call(Unknown Source)
            at aaf.vhr.LoginController.twosteplogin(LoginController.groovy:109)
            at aaf.vhr.LoginController.twosteplogin(LoginController.groovy)

Clearing the `two_step_session` entries for the user in question resolved the problem.

Best guess is you can't add and delete objects from the same association during a single transaction? Really not sure how this is handled by GORM.

![](http://i.imgur.com/8q4w9Sf.jpg)