Problem with java.lang.IncompatibleClassChangeError in conjunction with Kryo

Hello together,

I have a problem with the error handling of an Exception of the type java.lang.IncompatibleClassChangeError in Akka 2.6.3 using classic persistence.

Due to changes in the Kryo configuration one of my events is not recovered correclty. A field in the event that is defined as a Map is recovered as a String (however Kryo is able to create this state, I was not able to build a test case using reflection). When trying to iterate over this map, a java.lang.IncompatibleClassChangeError is thrown (an Error, not an Exception!).

That error never shows up in the onRecoveryFailure(…) handler. I also do not get the RecoveryCompeleted event and the actor never reaches its Recovered state, where the normal Receive handler is used. So basically the persistent actor is in a “dead” state, in which it does not produce any more messages and also is not able to receive any more messages. The supervisor does not get any error.

If I am catching that Error in my event handler and rethrow it as Runtime expception, the normal error handling works correctly. So for me it seems as if java.lang.Error Throwables are not handled correctly by Akka.

I had a look to the Scala Eventsourced source code. There I found the following:

  override def stateReceive(receive: Receive, message: Any) =
        try message match {
          case ReplayedMessage(p) =>
            try {
              eventSeenInInterval = true
              updateLastSequenceNr(p)
              Eventsourced.super.aroundReceive(recoveryBehavior, p)
            } catch {
              // *** This seems to be the problematic catch for me!!!! ***
              case NonFatal(t) =>
                timeoutCancellable.cancel()
                try onRecoveryFailure(t, Some(p.payload))
                finally context.stop(self)
                returnRecoveryPermit()
            }
          case RecoverySuccess(highestJournalSeqNr) =>
            ...

I am not sure if that is the correct code that handles my case. But if yes, it seems to me, as if the java.lang.Error is not seen as NonFatal error here and so falls through the catch block but is also not handled appropriatly somewhere up the callstack.

Is that really the case or am I supposed to handle my errors differently/configure the system differently?

Kind regards
Lay