Skip to content

Custom game hosting: server accepts game_host but never acts on the GameState Lobby relay — game stays closed/hosted_at:null, no HostGame sent #1099

Description

@asoftraiden

Summary

Hosting (and joining) custom games fails: the client hangs at "connecting" forever. Matchmaker games work normally.

With client TRACE logging enabled I captured the full lobby protocol in plaintext. The client sends {"command":"GameState","args":["Lobby"],"target":"game"} correctly, the websocket is demonstrably healthy in both directions, but the server never responds with HostGame and never transitions the game out of state: closed / hosted_at: null.

Because this only affects init_mode: 0 (custom) games and not matchmaker (init_mode: 1, which does not require the server→client HostGame/JoinGame GPGNet command), the problem is isolated to the server's handling of the GameState Lobby relay for custom games.

Environment

  • Client version: 2026.4.1 (downlords-faf-client)
  • Affected accounts: RaidenBoson (id 454005) and ASoft (id 450602)
  • Reproduced on two different machines, on two different accounts, and over a VPN (entirely different network path)
  • Windows 11

Reproduction

Click "Create Game" with any map/settings. The game launches, reaches GameState Lobby, and the lobby never opens.

Captured protocol trace

Third of three consecutive attempts (client logLevel: TRACE). Tokens are masked by the client itself.

00:47:02.314  Outbound: {"command":"game_host","mapname":"dualgap_adaptive.v0014","title":"Chill Game",
                         "mod":"faf","options":[],"access":"public","version":0,"password":null,
                         "visibility":"public","rating_min":null,"rating_max":null,
                         "enforce_rating_range":false}

00:47:02.437  Inbound:  {"command":"game_launch","args":["/numgames",814],"uid":27459407,"mod":"faf",
                         "name":"Chill Game","init_mode":0,"game_type":"custom","rating_type":"global"}

00:47:03.147  Inbound:  {"command":"game_info","uid":27459407,"title":"Chill Game","state":"closed",
                         "mapname":"dualgap_adaptive.v0014","host":"RaidenBoson","num_players":0,
                         "max_players":12,"hosted_at":null,"launched_at":null,"teams":{}}

00:47:35.902  Outbound: {"command":"GameState","args":["Idle"],"target":"game"}
00:47:36.116  Outbound: {"command":"GameState","args":["Lobby"],"target":"game"}

              (no HostGame; no further game_info for uid 27459407, ever)

The client-side emit is complete — the message is serialized and written, not dropped internally:

00:47:36.116 TRACE c.f.commons.lobby.FafLobbyClient : Sending message of type class com.faforever.commons.lobby.GpgGameOutboundMessage
00:47:36.116 TRACE c.f.commons.lobby.FafLobbyClient : Outbound message: {"command":"GameState","args":["Lobby"],"target":"game"}

The connection is healthy — this is not a dropped message

Counting inbound/outbound traffic after the GameState Lobby relay at 00:47:36, over the following ~6 minutes on the same websocket:

Message Count
game_info (other players' games) 503
player_info 145
matchmaker_info 43
ping (server → client) 8
pong (client → server) 8
game_info for our own uid 27459407 0

The server keeps pinging and the client keeps ponging, and the session is never timed out — so client→server frames are reaching the server. The server simply never acts on the GameState Lobby message and never broadcasts another update for the game it just created.

What has been ruled out

Request contents. Three consecutive attempts varying game_host fields, all failing identically:

  1. astro_crater_battles_4x4_rich_huge.v0004, rating_min: 900, rating_max: 3000, enforce_rating_range: true
  2. astro_crater_battles_4x4_rich_huge_by_lisnesta.v0004, same rating settings
  3. dualgap_adaptive.v0014, rating_min: null, rating_max: null, enforce_rating_range: false

All three maps are installed locally, and dualgap_adaptive.v0014 was being used by 69 other open games at the time.

Client side. The TRACE capture shows correct serialization and emission of GpgGameOutboundMessage.

ICE adapter. Connects, sends CreateLobby, receives GameState Lobby from the game, and relays it to the client correctly:

Sent GPGNet message: CreateLobby 0 42410 RaidenBoson 454005 1
Received GPGNet message: GameState Lobby
Sending Notification: {"method":"onGpgNetMessageReceived","params":["GameState",["Lobby"]],"jsonrpc":"2.0"}

Network / local environment. Matchmaker games work over the identical websocket, TLS session, ICE adapter and TURN relay. Also independently checked and excluded: DNS, MTU/PMTU, IPv6, packet loss, firewall, antivirus, Windows port reservations, ephemeral port exhaustion, and stale/zombie game processes. A clean client reinstall did not help.

Account / machine. Two accounts, two machines, and a VPN all reproduce it.

Failure occurs in windows, not at random

Hourly attempt/success counts for one day, taken from ice-adapter.log by counting Sent GPGNet message: CreateLobby (attempt) against Sent GPGNet message: HostGame (server responded):

Hour Attempts Successes
00 11 6
01 10 0
02 1 0
03 9 0
04 1 0
11 6 0
12 10 0
13 34 8
14 12 0
18 2 0
19 13 0
20 10 1
21 14 0
22 7 0
23 5 1

Inside a working window, CreateLobby and HostGame land in the same second, repeatedly. Outside one, it is 100% failure for hours. Nothing changes client-side across those boundaries.

Lifetime totals across all available logs: 266 custom-game attempts → 41 HostGame + 9 JoinGame returned.

Speculation

The windowed pattern would be consistent with the lobby connection being balanced across multiple server instances, where some instances have stuck or broken game-service state — leaving a client bound to a bad instance for the life of the websocket connection. I have no visibility into the server side to confirm this.

Happy to provide

Full TRACE client.log, ice-adapter.log, and game logs for any of the affected game UIDs (27459347, 27459382, 27459407) on request.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions