Quick answer: Trace the arithmetic feeding the assignment, guard the division and normalization steps, and add a development assert so the first NaN is caught where it is produced rather than where it lands.

Unity refuses NaN positions and names the object, which is a head start. The NaN was produced upstream of the assignment — often several frames earlier. Here is how to walk it back.

How to fix it

1. Guard normalize and divide

Replace dir.normalized with a length check (if (dir.sqrMagnitude > 1e-8f)) and never divide by Time.deltaTime or a distance that can be zero.

2. Check external inputs

Joystick axes after device changes, network snapshots, and save files can carry NaN — validate at the boundary with float.IsNaN before feeding them into movement.

3. Assert early in development

Wrap your movement integrator with a debug assert on the computed position so the stack trace points at the producing line, not the eventual assignment.

4. Recover instead of cascading

On detection at runtime, snap the entity to its last valid position and zero its velocity — one bad frame should not poison the session.

Catching the ones you can't reproduce

The hardest version of this to fix is the one you can't reproduce — it only happens on a player's hardware, OS, driver, or save state, under conditions that simply aren't present on your machine. A report that says “it crashed” or “it froze” gives you nothing to act on, so the bug survives release after release while quietly costing you players.

Automatic error capture closes that gap. Each failure arrives with its full stack trace, the device and OS, the build number, and a breadcrumb trail of what the player did right before it broke, so even a failure you have never seen becomes a specific, reproducible issue. Fold identical failures into one signature ranked by how many players each hits, and your worklist sorts itself worst-first instead of arriving as a stream of vague complaints.

This is where a tool like Bugnet earns its place. Its SDK captures every Unity error automatically with the full stack trace plus device, OS, memory, build, and game-state context, folds duplicates into one grouped issue with an occurrence count, and ties each to the build it first appeared on — so you fix the problem that hurts the most players first and confirm it is gone when its signature disappears from the next release.

The errors you never hear about are the ones quietly costing you players. Visibility turns them into a worklist.