NextGenerationReplication: a single server write to a client-owned object is delivered and applied many times

DESCRIBE THE ISSUE

With Workspace.NextGenerationReplication enabled and Server Authority off,
a single server-side write to an object owned by a client is received and
applied by that client repeatedly — typically 6–10 times, spaced roughly
50ms apart, over about 0.3–0.5 seconds.

An object owned by the server, in the same scene, in the same frame, under the
same latency, shows none of it.

This presents as several different-looking problems — physics jitter,
projectiles snapping back toward their spawn, and server-side character
teleports being undone — but they are all this one thing.

This is not a Studio artifact. We first hit it in our published experience
with real players on real connections, and it still occurs there. The attached
place reproduces it under Studio’s Network Simulation only because that is the
most convenient way to hand it to you — simulated latency makes the window
observable, it does not create the behaviour. The worse a player’s connection,
the worse it gets.

Setup (please read — nothing reproduces without it)

The attached place needs Network Simulation turned on, which the place
cannot do for itself. Fastest way is the command bar, before pressing Play:

local n=settings():FindService("NetworkSettings") n.InboundNetworkMinDelayMs=150 n.InboundNetworkJitterMs=150 n.OutboundNetworkMinDelayMs=150 n.OutboundNetworkJitterMs=150

Or set the four fields by hand in Studio Settings → Network.

Without simulated latency the retransmit window is too short to observe and the
place will look clean. It measures Player:GetNetworkPing() at startup and
prints a loud warning if latency appears to be off, so a misconfigured run
cannot be mistaken for a passing one.

Then press Play and walk around continuously — test D needs the character to
be moving, for reasons explained below.

Evidence 1 — a matched control

Two identical assemblies are launched in the same frame with the same velocity.
One is handed to the client with SetNetworkOwner(player); the other is
explicitly kept by the server with SetNetworkOwner(nil). Ownership is the only
variable. The client counts how many times each position is delivered to it:

A/control (SERVER-owned):  42 writes -> 42 distinct positions  (0 REDUNDANT)
A/subject (CLIENT-owned):   8 writes ->  1 distinct position   (7 REDUNDANT)
                            (14.00,12.00,0.00) delivered 8 TIMES
                            intervals 0.034 0.033 0.083 0.033 0.066 0.034 0.033 s

42 distinct positions is ordinary replication of a moving object. One position
delivered eight times is the bug.

Evidence 2 — it is not physics state, and not the ownership handoff

The server sets CanCollide = false exactly once, two full seconds after
ownership has settled. The client applies it 8 times:

intervals 0.050 0.034 0.036 0.020 0.078 0.054 0.062 s   (span 0.333s)

Across five runs: 6, 8, 8, 8 and 10 applications.

CanCollide is not physics state, so this is not the server continuing to
simulate the body. The write happens long after the handoff, so it is not a
race during ownership transfer.

This also means property-changed signals fire repeatedly. Any listener
hanging off a server-set property on a client-owned instance runs N times
instead of once. In our game a handler that disables colliders on a launched
projectile ran five times for a single server write.

Evidence 3 — the same thing on a player’s character

The server teleports the player’s character 60 studs with PivotTo. The
character arrives, and is then pulled back:

>>> PivotTo to z=63.47
    immediately after: server sees z=63.47
+0.2s  <-- back at the origin, the teleport was undone
+0.5s  68 studs from destination, 8 studs from origin

Measuring the character root the same way:

D/character:  9 writes -> 6 distinct positions (3 REDUNDANT)
              (14.30,3.13,63.47) delivered 4 TIMES
              intervals 0.050, 0.050, 0.050 s

The teleport destination itself is delivered four times at metronomic 50ms
spacing. Six distinct positions out of nine writes is what a walking player
should produce; the duplication sits on top of that.

The player has to be moving. A stationary player sends no position updates,
so there is nothing in flight to be redelivered, and the teleport appears to
work every time. This is why it took us several attempts to reproduce, and it
matches the real case exactly: players are essentially always moving when they
press a teleport button or leave a seat.

Timing

Every case shows regular spacing, ~20–130ms and clustering near 50ms, across a
span of 0.3–0.5s.

The duplicate count scales with latency — the worse the connection, the more
copies of a single write arrive. We have seen this consistently across Studio
latency settings and across real connections of differing quality in the
published game, though we have not sat down and plotted a curve.

Offered as a hypothesis rather than a claim: at 150ms each way an
acknowledgment needs ~300–400ms to get home, which is how long the bursts last.
That is consistent with retransmitting once per replication tick until the ACK
arrives, with the receiver applying every copy rather than discarding ones it
has already acted on. Scaling with latency fits — a longer round trip means
more ticks elapse before the acknowledgment lands, so more copies go out and
more get applied. We have no visibility into the transport, so this may be
wrong about the mechanism while the observations stand.

Why this matters

Server-side character teleports are not reliable for any moving player with
real-world latency. That is a primitive a great many experiences depend on —
spawns and respawns, seat and vehicle exits, teleport pads, cutscenes,
returning a player after an out-of-bounds check. It fails silently and looks
like a physics or exploit problem rather than a replication one.

Client-owned physics objects visibly jitter, because each duplicated
position write yanks them back.

Game logic double-fires, since change signals are raised once per delivery.

Severity scales with latency in two compounding ways: a laggier player both
receives more duplicate copies of each write and is more likely to have
stale state in flight to be redelivered. So it is worst for exactly the players
already having the roughest time — and it is happening to real players in
production now, not only under simulated conditions.

Why this may not have been reported yet

NextGenerationReplication is opt-in, and its headline purpose is enabling
Server Authority. With Server Authority on, this is largely invisible —
clients do not own the objects, so there is no client-owned assembly for a
server write to be duplicated onto.

We are running NextGenerationReplication with Server Authority off, which
appears to be the configuration that exposes it.

Our workaround, and why it is not a fix

For the systems where the client is the network owner, we re-assert the
client’s authoritative state in PreSimulation and reject incoming values we
can identify as stale — and for character teleports we hold the destination for
about a second after the move.

It is a band-aid. It costs per-object work every frame, it has to be added to
each system individually, and fundamentally it cannot distinguish a duplicate
from a legitimate server correction — it just guesses based on what it knows
about that particular object. Anything we forget to guard keeps the bug.

Reproduction file

NextGenReplicationBug.rbxl (76.3 KB)

The place contains four tests and a README explaining each. All output is
prefixed [REPRO][Server] or [REPRO][Client]; the client lines carry the
results.
Test A is the control comparison above and is the clearest single
piece of evidence.

Environment

  • Studio 0.732.0.7321043 (arm64), Apple M1 Max MacOS 26.3.1
  • Workspace.NextGenerationReplication = true
  • Workspace.AuthorityMode = Automatic
  • Network Simulation: 150ms delay + 150ms jitter, both directions
  • Reproduces in Play Solo and in Team Test
  • Also reproduces in a published experience with real players on real
    connections, with no Studio involvement and no simulated latency

Expected behavior

DESCRIBE WHAT YOU EXPECT TO HAPPEN

A single server-side write to a client-owned object should be observed by that
client exactly once, the same way it already is for a server-owned object.

Specifically:

  • Setting a property once server-side should raise one change signal on the
    client, not one per retransmission.
  • A server-side PivotTo on a player’s character should hold, whether or not
    that player is moving and whatever their latency.
  • Retransmission for reliability is expected and correct; the receiver applying
    every retransmitted copy, instead of discarding updates it has already acted
    on, is not.
5 Likes

I ran into the same issue you’re mentioning here, although the way you explain it is way more detailed. Hopefully Roblox fixes this soon as I would like to use NextGenerationReplication. Here’s my post.

https://devforum.roblox.com/t/workspacenextgenerationreplication-causes-rubberbands-when-manipulating-a-players-cframe

1 Like

Hi, thanks about this post.

We’ll investigate this

2 Likes

I believe this may be related, I tried the same setup in my post, but limited my fps to 60 and the issue did not occur. The only difference is the issue happened when AuthorityMode was set to Default/Off.
image