In Nakama, an object you assign to state gets copied
EraClash’s online matches run on Nakama with TypeScript modules. At one point commands and checksums were silently disappearing. There was no error, the result was just wrong.
The cause
Nakama’s JavaScript runtime converts the match state to Go values between loop calls. So an object or array you assign into the state is copied. If you change your reference after assigning it, the copy in the state never learns about it.
The example below shows the shape of the bug (it is not from the real code, it is written to explain):
// Wrong: changing the same reference after assigning it
state.turns[n] = commands;
commands.push(cmd); // the copy in state never sees this
// Right: build first, then assign
const next = [...commands, cmd];
state.turns[n] = next;
The fix
The rule is simple: build the value completely, then assign it. Do not touch the same object after assigning. I wrote this rule as a note at the top of the file that holds the lockstep logic, where it helps most. Command scheduling and checksum recording were reworked to follow it.
Why it was so sneaky
- It threw no error. When a command vanished, the simulation simply carried on without it.
- The logic lives in a separate file that does not depend on Nakama, and unit tests never showed this behavior, because the copying only happens inside Nakama’s runtime.
- Checksum comparison exists to catch desyncs; once the checksums vanished too, that safety net stopped working.
What I took from it
Behavior like “the environment silently copies your value” can be a small paragraph in the docs and still stretch debugging over days. Reading an environment’s data model up front is cheaper than debugging.