Skip to content

Bug: Chat message before WebSocket user initialization causes internal server error #965

Description

@tickBit

What doesn't work?

Sending a chat message immediately after the WebSocket connection opens can fail with an internal server error.

The WebSocket is already open from the client’s perspective, but the backend may not have finished initializing client.user yet. If the client sends a clanMessage before client.user is set, the backend throws:

TypeError: Cannot read properties of undefined (reading 'clanId')

What is the endpoint and method? (if applicable)

Endpoint: ws://localhost:8080/ws/chat

Method: WebSocket event clanMessage

How can it be reproduced?

  1. Start the backend locally.
  2. Sign in and get a valid JWT token.
  3. Open a WebSocket connection to ws://localhost:8080/ws/chat using the token.
  4. Send a clanMessage immediately in the client’s open handler, without waiting.
  5. The server may respond with Internal server error and log a TypeError because client.user is still undefined.

How should it be fixed?

The backend should not handle chat events before the WebSocket user context has been initialized.

Suggested changes:

  1. Add an explicit guard/check at the beginning of chat event handlers such as handleClanMessage, handleGlobalMessage, and reaction handlers:
if (!client.user) {
  throw new WsException('WebSocket user is not initialized yet');
}
  1. Return a controlled WebSocket error instead of allowing a TypeError.

  2. Optionally send a ready event to the client at the end of handleConnection(), after the player has been loaded and client.user has been assigned. The client can then wait for this event before sending chat messages.

Example:

{
  "event": "ready",
  "data": true
}

This removes the need for arbitrary client-side delays and makes the chat protocol deterministic.

Extra:

The following flow can be used to send a chat message in Powershell:

  1. $body = @{ username = "--username--" ; password = "--password--" } | ConvertTo-Json
    `

  2. $res = Invoke-RestMethod -Method Post -Uri "http://localhost:8080/auth/signIn" -ContentType "application/json" -Body $body

  3. send-chat.js:

const WebSocket = require("ws");

const token = process.argv[2];

if (!token) {
  console.error("Token puuttuu. Aja: node .\\send-chat.js SINUN_TOKEN");
  process.exit(1);
}

const sock = new WebSocket("ws://localhost:8080/ws/chat", {
  headers: {
    Authorization: "Bearer " + token,
  },
});

sock.on("open", () => {
  console.log("connected");

  setTimeout(() => {
    sock.send(JSON.stringify({
      event: "clanMessage",
      data: {
        content: "Testiviesti lokaaliymparistosta",
      },
    }));
  }, 1000);

  setTimeout(() => {
    sock.close();
  }, 3000);
});

sock.on("message", (message) => {
  console.log(message.toString());
});

sock.on("error", (error) => {
  console.error(error);
});

sock.on("close", () => {
  console.log("closed");
});
  1. node .\send-chat.js $env:TOKEN

Please don't include send-chat.js into commits to repo.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't working

Type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions