#978·colyseus

[Bug]: createRoom's ipc_timeout fallback creates a duplicate room

Author: brobinettCreated Sep 22, 2026Updated Sep 22, 2026
Labels:bug: bug:eyes: triage

Context

Same setup as #968, Pokemon Auto Chess, found while reproducing that one. It's a separate path: #968 is a listing that gets removed, this is a second room that gets created.

Bug description

MatchMaker.createRoom publishes an IPC create request to the selected process, waits REMOTE_ROOM_SHORT_TIMEOUT, and on ipc_timeout creates the room locally instead. The request it already published is never revoked, so a process that was stalled rather than dead drains it on recovery and creates the room too. One request, two rooms on two processes.

How it manifests in PAC: PAC rooms set autoDispose = false and build their player list from the creation options, so the orphan is populated: it holds 8 players who are all actually playing in the other room, starts itself after the loading timeout, plays out the match, and writes ELO even if no one ever connects.

It isn't rare. Anecdotally it is quite commonly reported in the PAC discord, and it was easy to reproduce. Forcing the create timeout produced a twin in 42 of 44 test runs across 0.17.51 and 0.18.14

I just opened a PR to work around it in the application (keldaanCommunity/pokemonAutoChess#4128): every room checks a per-call creation id in presence and disposes itself if the key names another room. It's a bandaid, it doesn't stop the second room being created, just detects and deletes it.

Reproduction

No response

Steps to reproduce

  1. Run two processes against one Redis, with RedisDriver and RedisPresence.
  2. Define a room that sets autoDispose = false.
  3. SIGSTOP the process that selectProcessIdToCreateRoom picks.
  4. Issue one ordinary room creation at the other process.
  5. Wait out REMOTE_ROOM_SHORT_TIMEOUT, so the caller falls back and creates the room locally.
  6. SIGCONT the stopped process.

It drains the create request it was holding and creates the room as well. Both rooms are then running, on different processes, from the one request.

Environment & Versions

Colyseus version: 0.17.51 and 0.18.14, both with @colyseus/redis-driver and @colyseus/redis-presence Node.js version: 23.6.0 for the reproduction, 24 in production TypeScript version: 5.9.3 Redis version: 8.10.0 Operating system: Linux PAC runs 8 processes across 4 machines in prod