This was fun. I was looking into a plugin that wasn't behaving as expected, particularly around an array of structs that was being replicated. Scanning through the code, the problem became obvious quite quickly. The author had a TArray of UStructs on the server, that was being manipulated on the server, and replicated to clients. So far, so good!

On the client however, the author had an OnRep function that executed on replication, which read the entries in the array and did some logic, and then deleted the contents of the array. The comments in the code indicated that the author was attempting to use the replicated array as a network message queue of sorts, where new or modified entries get added on the server, processed on the client when it's replicated, then removed from the queue.

This is not how replicated arrays work! The replication system attempts to keep the state of properties in sync between server and client. This is quite straightforward with single structs, but with arrays, it uses the array index to track and serialise dirty properties that need replicating. For this to work, the replication system needs to know that the state of the array on the client is consistent. So when item at index 5 is modified on the server, we really need to be sure that same item is still at index 5 on the client! If we do what this plugin does, and modify the property on the client, at the same time as the replication system is trying to send and apply change deltas to the client, we're going to have a really bad time. We may be replicating properties on an entirely different array element, or even out of bounds.

Don't Modify Replicated Properties On The Client

The solution to this is simple : Do not ever, ever, modify replicated properties on the client.

When you mark a property as replicated, you are saying to the engine, 'keep this property in sync with the server'. If you don't want it to be in sync with the server, then do not use property replication. 

If you are modifying a replicated property on the client, it stands to reason that you want to read that value again at some point. With a replicated property, you have absolutely no idea when that value is going to be overwritten by the replication system, it's a recipe for expensive, intermittent bugs and many wasted hours debugging.