Quick answer: Netcode for GameObjects crashes mostly happen around the NetworkManager lifecycle: objects spawn and despawn asynchronously, RPCs and NetworkVariables fire across the server and client boundary, and ownership shifts mid session. To fix them, capture the NetworkManager state, whether the build is server, client, or host, the netId and owner of the object, and the RPC or NetworkVariable in flight. Group by that signature and lifecycle races become clear.
Unity Netcode for GameObjects, or NGO, is Unity's first party networking solution, and it centralizes everything through the NetworkManager. That central role is also where most production crashes originate, because NGO spawns objects, replicates NetworkVariables, and routes ServerRpc and ClientRpc calls asynchronously across the connection. In editor with a host and a local client, those operations complete almost instantly and in a predictable order. Shipped to players on real networks, the same operations race: an RPC arrives before a spawn, a NetworkVariable updates an object mid despawn, and ownership changes catch your code off guard. This post covers how to capture the NGO context that makes those crashes reproducible.
The NetworkManager lifecycle as a crash surface
Everything in NGO flows through the NetworkManager: it tracks whether you are a server, client, or host, owns the spawn manager, and drives connection events. Many crashes happen because code runs at a lifecycle moment the NetworkManager is not ready for, such as accessing a spawned object during shutdown, calling an RPC before the network has started, or handling a connection callback after the manager has already torn down. The stack trace shows the line but not the lifecycle moment, which is what actually mattered.
Capturing the NetworkManager state at crash time, whether it is listening, the build role, and whether a shutdown was in progress, reframes the report. A NullReferenceException inside a connection approval callback during shutdown is a teardown race, not a logic bug, and you only know that if the lifecycle state rides along with the crash. NGO crashes are stateful in the same way Photon and Mirror crashes are, so the network manager state is the first context to capture for every report.
Spawn, despawn, and the ownership model
NGO spawns NetworkObjects on the server and replicates them to clients asynchronously, so there is always a window where a client references an object that has not spawned locally yet or was just despawned. An RPC or NetworkVariable change targeting such an object throws, and the crash depends purely on timing. Recording the netId and whether the object was spawned and active at crash time separates these spawn races from genuine logic errors that would fire regardless of timing.
Ownership is the other NGO specific dimension. NetworkObjects have an owner, ownership can be transferred, and ServerRpc calls are gated by ownership. A common crash is a client invoking a ServerRpc on an object it no longer owns, or your code assuming IsOwner during a frame where ownership just changed. Capturing the owner client id and the IsOwner and IsServer flags at crash time tells you immediately whether you are looking at an ownership mistake, which is a very different fix from a null in shared logic.
RPCs and NetworkVariables in flight
NGO crashes frequently fire while processing a ServerRpc, a ClientRpc, or a NetworkVariable change, so recording which one was in flight and its direction is high value context. A ServerRpc that deserializes client input into invalid game state is both a stability and a trust problem; a ClientRpc that runs on a client whose object is mid scene change throws because the target is gone. The same generic exception traces back to a specific message once you know which one was being handled.
NetworkVariables add a subtler failure mode: their OnValueChanged callbacks fire on clients when the server updates a value, and if your callback assumes other state has already synced, it crashes during the brief window where values arrive out of your expected order. Capturing which NetworkVariable changed and the old and new values, where practical, turns these from mysterious client side nulls into a clear story about replication order. Knowing the message and direction points you at the exact contract to harden rather than guessing.
Host mode and connection edge cases
Like Mirror, NGO supports host mode where one process is both server and client, and it executes code paths neither pure role hits alone. Host crashes often reveal a method that assumed it ran only on the server or only on a client. Tagging the role as host, separate from server and client, lets you isolate these. Connection approval, late joins, and reconnections are the other edge cases that crash NGO games, because they exercise the lifecycle at its most fragile moment.
Capture the connection state and whether a scene transition was underway, since NGO scene management despawns and respawns objects and is a frequent crash trigger. A client that joins during a host scene load, or disconnects while a NetworkVariable batch is in flight, hits code paths your steady state testing never reaches. The connection context lets you tell apart a clean logic bug from one that only fires during the join, leave, and scene change transitions that dominate real NGO crash reports.
Setting it up with Bugnet
Bugnet captures NGO crashes with their full Unity stack trace and device context, and its in game report button snapshots game state automatically so you also see the scene and the moment of failure. To make NGO tractable, use custom fields to attach the NetworkManager role and listening state, the netId and owner of the crashing object, the IsOwner and IsServer flags, and the RPC or NetworkVariable in flight. Those fields convert an ambiguous lifecycle null into a precisely located spawn, ownership, or replication bug in one dashboard.
Bugnet folds duplicate reports into a single grouped issue with an occurrence count, which is exactly right for NGO crashes that recur across many sessions and roles. You see that an OnValueChanged crash hit 210 times, all on clients, all during scene transitions, and you prioritize it over a rarer ownership bug on the server. Filtering by role, owner, or message lets you confirm the pattern and verify a fix, so you ship changes targeted at the NGO transition that is actually hurting the most players.
A repeatable NGO crash workflow
Wire the NetworkManager state and role into your reporting once so every NGO crash inherits the lifecycle context for free. It is a handful of lines reading NetworkManager.Singleton at report time, and it removes the worst ambiguity from your data permanently. From there, your habit is to read every crash through the lens of which lifecycle moment and which role it hit, rather than treating the stack trace as complete. The reports start telling you where to look instead of merely where it broke.
Test the join, leave, scene change, and ownership transfer paths deliberately before each release, including host mode, since those are where NGO concentrates its crashes. When grouped reports point at one transition, you reproduce it directly with simulated latency and late joins. Over time your spawn checks, ownership guards, and NetworkVariable callbacks grow robust because every crash that reaches you carries the lifecycle and message context needed to fix it at the source.
NGO crashes are about lifecycle, not just lines. Capture the NetworkManager state, the owner, and the message in flight, and a mysterious null becomes a clear spawn or ownership race.