Trying to enable Iris leads to crash: Assertion failed: ArraySerializer.IDCounter == 0 && ArraySerializer.ArrayReplicationKey == 0

I tried to enable Iris in my game, which is originated from Lyra 5.1 template, I tried to do this both in 5.1 and in 5.2, where Iris is precompiled, but in both cases I got the following crash as soon as client tried to spawn a character:

Assertion failed: ArraySerializer.IDCounter == 0 && ArraySerializer.ArrayReplicationKey == 0 [File:C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Net\\Core\\Classes\\Net\\Serialization\\FastArraySerializer.h] [Line: 861] ECREditor_GameplayAbilities!FFastArraySerializer::TFastArraySerializeHelper<FReplicatedPredictionKeyItem,FReplicatedPredictionKeyMap>::BuildChangedAndDeletedBuffersFromDefault() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Net\\Core\\Classes\\Net\\Serialization\\FastArraySerializer.h:861] ECREditor_GameplayAbilities!FFastArraySerializer::FastArrayDeltaSerialize_DeltaSerializeStructs<FReplicatedPredictionKeyItem,FReplicatedPredictionKeyMap>() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Net\\Core\\Classes\\Net\\Serialization\\FastArraySerializer.h:1749] ECREditor_GameplayAbilities!FFastArraySerializer::FastArrayDeltaSerialize<FReplicatedPredictionKeyItem,FReplicatedPredictionKeyMap>() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Net\\Core\\Classes\\Net\\Serialization\\FastArraySerializer.h:1364] ECREditor_Engine!FRepLayout::SendCustomDeltaProperty() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Engine\\Private\\RepLayout.cpp:4540] ECREditor_Engine!FObjectReplicator::SendCustomDeltaProperty() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Engine\\Private\\DataReplication.cpp:380] ECREditor_Engine!FObjectReplicator::InitRecentProperties() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Engine\\Private\\DataReplication.cpp:449] ECREditor_Engine!FObjectReplicator::InitWithObject() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Engine\\Private\\DataReplication.cpp:553] ECREditor_Engine!UNetConnection::CreateReplicatorForNewActorChannel() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Engine\\Private\\NetConnection.cpp:3840] ECREditor_Engine!UActorChannel::CreateReplicator() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Engine\\Private\\DataChannel.cpp:4785] ECREditor_Engine!UActorChannel::WriteSubObjectInBunch() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Engine\\Private\\DataChannel.cpp:4933] ECREditor_Engine!UActorChannel::ReplicateRegisteredSubObjects() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Engine\\Private\\DataChannel.cpp:3642] ECREditor_Engine!UActorChannel::DoSubObjectReplication() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Engine\\Private\\DataChannel.cpp:3532] ECREditor_Engine!UActorChannel::ReplicateActor() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Engine\\Private\\DataChannel.cpp:3394] ECREditor_Engine!UNetDriver::ProcessRemoteFunctionForChannelPrivate() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Engine\\Private\\NetDriver.cpp:2124] ECREditor_Engine!UNetDriver::InternalProcessRemoteFunctionPrivate() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Engine\\Private\\NetDriver.cpp:2029] ECREditor_Engine!UNetDriver::ProcessRemoteFunction() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Engine\\Private\\NetDriver.cpp:6598] ECREditor_Engine!UActorComponent::CallRemoteFunction() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\Engine\\Private\\Components\\ActorComponent.cpp:795] ECREditor_CoreUObject!UObject::ProcessEvent() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Source\\Runtime\\CoreUObject\\Private\\UObject\\ScriptCore.cpp:1999] ECREditor_GameplayAbilities!UAbilitySystemComponent::NetMulticast_InvokeGameplayCueAdded_WithParams() [C:\\Users\\JediKnight\\Documents\\Unreal Projects\\ECR\\Intermediate\\Build\\Win64\\ECREditor\\Inc\\GameplayAbilities\\UHT\\AbilitySystemComponent.gen.cpp:1331] ECREditor_GameplayAbilities!IAbilitySystemReplicationProxyInterface::Call_InvokeGameplayCueAdded_WithParams() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Plugins\\Runtime\\GameplayAbilities\\Source\\GameplayAbilities\\Public\\AbilitySystemReplicationProxyInterface.h:64] ECREditor_GameplayAbilities!UAbilitySystemComponent::AddGameplayCue_Internal() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Plugins\\Runtime\\GameplayAbilities\\Source\\GameplayAbilities\\Private\\AbilitySystemComponent.cpp:1352] ECREditor_GameplayAbilities!UAbilitySystemComponent::AddGameplayCue_Internal() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Plugins\\Runtime\\GameplayAbilities\\Source\\GameplayAbilities\\Private\\AbilitySystemComponent.cpp:1307] ECREditor_GameplayAbilities!UAbilitySystemComponent::AddGameplayCue_MinimalReplication() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Plugins\\Runtime\\GameplayAbilities\\Source\\GameplayAbilities\\Private\\AbilitySystemComponent.cpp:1295] ECREditor_GameplayAbilities!FActiveGameplayEffectsContainer::AddActiveGameplayEffectGrantedTagsAndModifiers() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Plugins\\Runtime\\GameplayAbilities\\Source\\GameplayAbilities\\Private\\GameplayEffect.cpp:3446] ECREditor_GameplayAbilities!FActiveGameplayEffect::CheckOngoingTagRequirements() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Plugins\\Runtime\\GameplayAbilities\\Source\\GameplayAbilities\\Private\\GameplayEffect.cpp:1779] ECREditor_GameplayAbilities!FActiveGameplayEffectsContainer::InternalOnActiveGameplayEffectAdded() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Plugins\\Runtime\\GameplayAbilities\\Source\\GameplayAbilities\\Private\\GameplayEffect.cpp:3329] ECREditor_GameplayAbilities!FActiveGameplayEffectsContainer::ApplyGameplayEffectSpec() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Plugins\\Runtime\\GameplayAbilities\\Source\\GameplayAbilities\\Private\\GameplayEffect.cpp:3275] ECREditor_GameplayAbilities!UAbilitySystemComponent::ApplyGameplayEffectSpecToSelf() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Plugins\\Runtime\\GameplayAbilities\\Source\\GameplayAbilities\\Private\\AbilitySystemComponent.cpp:842] ECREditor_GameplayAbilities!UAbilitySystemComponent::ApplyGameplayEffectToSelf() [C:\\Users\\JediKnight\\Documents\\UnrealEngine\\Engine\\Plugins\\Runtime\\GameplayAbilities\\Source\\GameplayAbilities\\Private\\AbilitySystemComponent.cpp:536] ECREditor_ECR!UECRAbilitySet::GiveToAbilitySystem() [C:\\Users\\JediKnight\\Documents\\Unreal Projects\\ECR\\Source\\ECR\\Private\\Gameplay\\GAS\\ECRAbilitySet.cpp:117]

So, on character spawn, server tries to give out ability set, which has a gameplay effect in it with a gameplay cue.

Gameplay cue triggers a multicast, this seems to be a the first to the replication for this actor, because UActorChannel::CreateReplicator() is called, in the end we try to open an actor channel for AbilitySystemComponent on the character.

The changer that causes the crash seems to be this part in FObjectReplicator::SendCustomDeltaProperty, it wasn’t enabled without Iris:

#if UE_WITH_IRIS
   // When initializing baselines we should not modify the source data if it originates from the CDO or archetype
   Parms.bIsInitializingBaseFromDefault = Parms.Object && Parms.Object->HasAnyFlags(RF_ClassDefaultObject | RF_ArchetypeObject);
#endif

Now, for some strange reason, my instanced AbilitySystemComponent on the character has a flag RF_ArchetypeObject. I checked that this flag is removed after some time, so it’s probably only here in the frame when the actor spawns.

And while we are trying to replicate ReplicatedPredictionKeyMap from ASC, because of that bool, inside FFastArraySerializer::FastArrayDeltaSerialize_DeltaSerializeStructs we fall into this pathway:

if (Parms.bIsInitializingBaseFromDefault)
{
   Helper.BuildChangedAndDeletedBuffersFromDefault(NewItemMap, ChangedElements); // this pathway
}
else
{
   Helper.BuildChangedAndDeletedBuffers(NewItemMap, OldItemMap, ChangedElements, Header.DeletedIndices); // instead of this
}

BuildChangedAndDeletedBuffersFromDefault expects this assert:

check(ArraySerializer.IDCounter == 0 && ArraySerializer.ArrayReplicationKey == 0);

But my ArraySerializer.ArrayReplicationKey is 448, probably due to the changes inside ReplicatedPredictionKeyMap, which was modified by happening ASC events like gameplay cues or whatever.

Now, how should this be resolved:

  1. Why instanced Ability System Component has an archetype flag for a short time? I think also saw this flag for some other replicated components.

  2. Should it have this flag or not? I guess no, but it may be Iris trying to reconstruct new replication state from cdo state using deltas or whatever.

  3. If it should have this flag, how do I ensure that ArraySerializer.ArrayReplicationKey == 0

===

For now I just commented out that part that checks if an object is a CDO, I don’t really get this part about replicated CDOs, and my game seems to launch and execute basic functionality fine, but I wonder where it will lead me in the future…