I’ve found a bug in the replication graph for multicast RPCs not considering whether the receiving connection is even ready to receive a new actor channel. We’ve gone ahead and made the following changes to ReplicationGraph.cpp, around like 2477:
Mainly posting for visibility, or if this is not the correct fix, advisement on a more proper fix. But this has fixed the issue for us when the server performs a reliable multicast rpc on an actor that does not go dormant, where the client would prematurely destroy said actor when completing its seamless travel and never receive further updates.
//UE_CLOG(ConnectionActorInfo.Channel == nullptr, LogReplicationGraph, Display, TEXT("Null channel on %s for %s"), *GetPathNameSafe(Actor), *GetNameSafe(Function));
if (ConnectionActorInfo.Channel == nullptr && (RPC_Multicast_OpenChannelForClass.GetChecked(Actor->GetClass()) == true))
{
// There is no actor channel here. Ideally we would just ignore this but in the case of net dormancy, this may be an actor that will replicate on the next frame.
// If the actor is dormant and is a distance culled actor, we can probably safely assume this connection will open a channel for the actor on the next rep frame.
// This isn't perfect and we may want a per-function or per-actor policy that allows to dictate what happens in this situation.
// Actors being destroyed (Building hit with rocket) will wake up before this gets hit. So dormancy really cant be relied on here.
// if (Actor->NetDormancy > DORM_Awake)
{
bool bShouldOpenChannel = true;
#if WITH_ENGINE_CHANGES
// Kyle - 6/29/2026. Fixing a bug where we are opening a channel for an actor that shouldn't be. e.g. not the same level.
if (!NetDriver->IsLevelInitializedForActor(Actor, NetConnection))
{
bShouldOpenChannel = false;
UE_LOG(LogReplicationGraph, Warning, TEXT("Multicast RPC opening channel for actor that is not initialized on connection. Actor: %s Target: %s Function: %s"), *GetNameSafe(Actor), *GetNameSafe(TargetObj), *GetNameSafe(Function));
}
else
#endif
if (ConnectionActorInfo.GetCullDistanceSquared() > 0.f)
{
bShouldOpenChannel = false;
if (ActorLocation.IsSet() == false)
{
ActorLocation = Actor->GetActorLocation();
}
[Attachment Removed]