A WebSocket client joining before the server allowed it
Socket.io handleConnection is async and sets client.data.token only after awaiting, so a fast client reached the join handler before auth finished and found no token.
It could not have worked
A race, an ordering, one column holding two things. The shape ruled it out before the code ran.
Found during a production-depth review, not from a report. RealtimeGateway.handleConnection is async — it resolves the token and only then sets client.data.token. But that firing and the client's next action (joining a conversation room, which the frontend does immediately) aren't ordered relative to each other. A fast client could reach handleJoin before the async work finished, find no token, and get silently disconnected through no fault of its own.
A manual click-test would almost never catch this, since the resolution usually finishes well within a round-trip. It would surface as an intermittent "sometimes messaging just doesn't connect," which is the worst kind of ticket.
handleJoin now re-derives the token from the handshake if the cached value isn't there. Verified with a standalone socket.io-client script hammering the join-on-connect sequence, 5/5 clean after previously reproducing the disconnect. An async connection handler that sets state other handlers depend on is a race by construction — worth asking "what if the next message arrives before this promise settles" every time.