Quick answer: With Iris, a UPROPERTY(Replicated) that worked on the legacy network driver may silently stop replicating because Iris builds a different internal fragment list. Keep GetLifetimeReplicatedProps wiring intact, verify the actor is actually Iris-managed via console commands, and confirm the client is relevant to the actor. Missing any of these and Iris quietly excludes the property.
Unreal 5.4 introduced Iris as the next-generation networking stack, and 5.5 made it production-viable. If you enable it mid-project, you will almost certainly hit a case where a property that replicated yesterday stops replicating today — with no compile error and no log message. The fix is mechanical once you know where Iris differs from the legacy path.
The Symptom
You set net.Iris.UseIrisReplication 1 (or flip the project setting) and run a multiplayer PIE session. The server changes a UPROPERTY(ReplicatedUsing = OnRep_Health) value. The server’s own character updates. The client never sees the change, and OnRep_Health never fires on the client. No warning in the log.
Variant: the property replicates to one client but not another. Or the property replicates during a short window after spawn and then freezes. Or it replicates for Pawns but not for components.
What Causes This
1. Iris was never actually enabled. The project setting toggles the subsystem, but individual actors are opted in by presence of a UIrisComponent (or by bReplicateUsingRegisteredSubObjectList + Iris-compatible configuration). If your actor was spawned before the flag flipped, it may still be on the legacy path.
2. Missing fragment for non-primitive type. Iris wraps POD replication in fragments. Types like TMap, custom structs with NetSerialize, or replicated TArray<struct> may need an explicit fragment registration if the generated header did not emit one for the Iris path.
3. GetLifetimeReplicatedProps not called or skipped. Iris still reads GetLifetimeReplicatedProps for compatibility. If the function is missing (for example, if you replaced it with a custom system), Iris’s fragment registration sees zero properties to replicate.
4. ReplicationCondition or NetCull excludes the client. Iris is stricter about relevance than the legacy path. A Net Cull Distance of 10000 that was “close enough” before may now be beyond the relevance cell — the property simply does not send to that client.
5. Component replicated separately from owner. On Iris, sub-objects and components use the RegisteredSubObjectList path. If you forgot to call AddReplicatedSubObject, the component exists on clients but its properties do not sync.
The Fix
Step 1: Prove Iris is on for this actor.
// Console on the server:
// net.Iris.UseIrisReplication 1
// net.Iris.PrintReplicationStatus
// Expect to see your actor listed as Iris-managed.
// In code:
if (UE::Net::FReplicationSystem* RepSys = World->GetNetDriver()->GetReplicationSystem()) {
UE_LOG(LogNet, Log, TEXT("Iris is active: %d"), RepSys != nullptr);
}
Step 2: Keep GetLifetimeReplicatedProps correct. This still drives Iris’s fragment list.
// MyCharacter.h
UCLASS()
class AMyCharacter : public ACharacter {
GENERATED_BODY()
public:
UPROPERTY(ReplicatedUsing=OnRep_Health)
float Health = 100.f;
UPROPERTY(Replicated)
FGameplayTagContainer ActiveEffects;
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& Out) const override;
UFUNCTION()
void OnRep_Health(float OldHealth);
};
// MyCharacter.cpp
void AMyCharacter::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& Out) const {
Super::GetLifetimeReplicatedProps(Out);
DOREPLIFETIME(AMyCharacter, Health);
DOREPLIFETIME_CONDITION(AMyCharacter, ActiveEffects, COND_OwnerOnly);
}
Step 3: Register replicated sub-objects explicitly. If your replicated property lives on a UActorComponent, make sure the component is on the actor’s sub-object list.
void AMyCharacter::BeginPlay() {
Super::BeginPlay();
if (HasAuthority() && InventoryComponent) {
// Tell Iris this component participates in replication
AddReplicatedSubObject(InventoryComponent);
}
}
// Also ensure bReplicateUsingRegisteredSubObjectList is true
AMyCharacter::AMyCharacter() {
bReplicateUsingRegisteredSubObjectList = true;
SetReplicates(true);
}
Step 4: Audit replication conditions and relevance.
// Debug command to trace why a property didn’t send to a client:
// net.Iris.PrintReplicationStatus
// net.Iris.DebugActor MyCharacter_C_1
// Check relevance in code:
bool AMyCharacter::IsNetRelevantFor(
const AActor* RealViewer,
const AActor* ViewTarget,
const FVector& SrcLocation) const
{
const bool bBase = Super::IsNetRelevantFor(RealViewer, ViewTarget, SrcLocation);
UE_LOG(LogNet, Verbose, TEXT("Relevant for %s: %d"),
*RealViewer->GetName(), bBase);
return bBase;
}
Step 5: Use Iris-safe custom structs. If you have a struct with a custom NetSerialize, add a NetDeltaSerialize or register an Iris serializer. For most gameplay structs, adding WITH_NET_SERIALIZER in the struct traits is enough.
Step 6: Flip Iris off to confirm the split. If the property replicates fine with net.Iris.UseIrisReplication 0, the problem is Iris-specific. If it still fails, it is a broader replication problem not specific to Iris.
Why This Works
Iris replaces the legacy per-actor FObjectReplicator with a fragment-based system that batches properties across actors, tracks dirtiness at a finer granularity, and uses a dedicated relevance oracle instead of the old per-frame IsNetRelevantFor walk. The benefits are enormous — 2–10x more replicated actors on a single server in stress tests — but the cost is a stricter setup contract.
Fragment registration is how Iris knows what to serialize. Without a fragment, the property is invisible to the replication graph even if it is dirty. Iris reuses GetLifetimeReplicatedProps to auto-generate fragments for simple types, but custom structs and sub-objects need explicit hints.
The sub-object list is the second gotcha. Legacy replication walked every component on every actor every tick. Iris requires components to opt in, which is faster but silently excludes anything you forgot to add.
"Iris does not replicate properties; it replicates fragments. If your property is not in a fragment, it does not exist on the wire."
Related Issues
For general replication debugging, see Fix: Unreal Replicated Actor Spawns Missing on Client. If RPCs misfire under Iris, check Fix: Unreal Server RPC Dropped on Client.
Iris: fragments are real, relevance is strict, sub-objects are opt-in. Miss one, get silence.