"[Sync] component created after NetworkSpawn silently never replicates"
▸ SYMPTOM
A component's [Sync] fields update correctly on the owner but are always zero/default on every other peer. No error anywhere — the owner writes a value, a host-side probe confirms it, but the client's proxy instance stays at the initial value forever.
▸ CAUSE
NetworkSpawn runs before OnStart. If a component with [Sync] state is created in OnStart (e.g. via Components.GetOrCreate<MyState>()), it wasn't in the spawn snapshot. Each peer ends up creating its own local instance of the component — the owner's instance has no network-paired counterpart on the client, so [Sync] fields never cross the wire. There's no error because the component exists on both sides; it's just not the same network entity.
This pattern often creeps in when you already have sync-free helper components that are safely created in OnStart via GetOrCreate — extending that pattern to a component with [Sync] fields silently breaks replication.
▸ FIX
Create the component in the spawn path, before go.NetworkSpawn(owner):
// In your spawn/setup code — BEFORE NetworkSpawn
var go = scene.CreateObject();
go.Components.Create<MyCharacter>();
go.Components.Create<MyState>(); // has [Sync] fields — must exist pre-spawn
go.NetworkSpawn(owner);OnStart's GetOrCreate then finds the replicated instance on every peer instead of creating a competing local one.
Rule of thumb: components that only read/tick locally may be created any time. A component that carries [Sync] state must exist before NetworkSpawn.
▸ WHY IT WORKS
NetworkSpawn snapshots every component on the GameObject at call time and assigns them network identity. Components added after this point have no cross-peer identity — [Sync] only works when both sides are talking about the same network entity. Creating the component pre-spawn ensures it's included in the snapshot and gets a proper network pair on every connecting peer.