I've been looking into how to fix this and I wanted to share this with you and see if you had any comments. Note first that I've updated the JIRA and I can now replicate it with a simple pojo. No need for multi references.

The issue appears when reading a Person object (i.e. p1) and while reading p1's address, this person (p1) gets evicted.

One of the problems I see already in the eviction is that when a node is evicted, the dynamic interceptor is not removed at eviction. Currently, the cache interceptor removal is done in CacheInterceptor.isPojoDetached() next time the pojo is read and it discovers that there's no pojo in the cache any more. If eviction happens between call to isPojoDetached() and call to cache.getObject() in CacheInterceptor.invoke(), then the following issue occurs:

Pojo Cache discovers that a Pojo was evicted but someone else was reading it so it decides to restore p1 in cache but the issue comes when it needs to deal with the cache interceptor is still there. As it's there, it thinks there's the possibility of an object graph so it goes onto setting up reference count and at that point realises that the AOPInstance in that FQN is gone and it then throws that Exception.

So, one option, and my preferred one would be to remove, if present, the cache interceptor during eviction. I've quickly tried this solution and it worked. Dunno however what other implications this could have. Previous experience on this area from Jason/Brian/Manik would be appreciated.

The other option I had in mind would be for ObjectGraphHandler.objectGraphPut() to deal with RuntimeException (obviously, some other more specific exception than that!) coming from InternalDelegate.incrementRefCount() in a more silent way, i.e. return false.

I don't see anything wrong with removing the dynamic interceptor on eviction. In fact, regardless of the concurrent read case, I think the dynamic interceptor not being removed on eviction is a bug. Jason? Thoughts?

I'd have to look at the code again, but the interceptor should probably remain, otherwise susequent calls on the object will return the object's field (instead of the cached version) which would be indeterminate.

With the current code, the moment the pojo has been evicted and you call one of it's set/get methods, the cache interceptor will be removed, so the indeterminism is already present, even before the suggested change.

If we're gonna fix the indeterminism at some point, we'll need some option to cope with both scenarios, since there might be users already relying on this.