partyserver: with hibernation off, a closing socket removes a newer connection with the same id from getConnections(), so that client stops receiving broadcasts
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 82/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- typescript
- Domain
- backend
Research direction
Start with InMemoryConnectionManager.accept and removeConnection, where the issue identifies the map entry and close/error listener. Check the tests for connection replacement and delayed close events, then verify that closing an older socket leaves the newer connection available through getConnections(). Done means the replacement connection continues receiving broadcasts after the old socket closes.
Written by the indexing model from the issue text.
Description
InMemoryConnectionManager.accept stores connections in a Map keyed by connection.id. Its close/error listener runs this.#connections.delete(connection.id) without checking that the entry is still that connection.
y-partyserver's YProvider sends one _pk (from connectionId, or nanoid(10) once per provider) on every reconnect. So a client that reconnects while the server still holds its old socket replaces the map entry. When the old socket's close arrives later, the delete removes the new, live connection. From then on getConnections() never yields it. The client keeps sending and the server keeps applying its updates, but no broadcast reaches it: with y-partyserver that is every document update and every awareness change from the other peers. Nothing tells the client, and the provider has no watchdog for a silent socket, so it stays deaf until it reconnects for some other reason.
Repro (partyserver 0.5.10, y-partyserver 2.2.0, wrangler 4.159.0, compatibility date 2026-11-01, hibernate: false, via unstable_startWorker). A and B are YProviders in one room:
- Open a raw WebSocket to the room with
?_pk=<A.provider.id>. It stands in for an old socket the server has not seen die yet. - Connect A, then terminate the raw socket and wait 1.5 s.
- A's updates still reach B. But within 3 s, none of these reach A: B's updates, B's awareness change, and the updates of a newcomer C.
The result is the same when the raw socket opens after A. Without the raw socket, all of these checks pass.
Suggested fix: in removeConnection, delete only when this.#connections.get(connection.id) === connection. The older socket then leaves the map as soon as it is replaced, which fits: it is the stale one.
- Dominant language
- TypeScript
- Stars
- 1.3k
- Forks
- 86
- PR merge metrics
- No merged PRs in 30d
Getting set up
- No Dockerfile or Docker Compose file
- No pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from cloudflare/partykit
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
cloudflare/partykit#444 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 68/100
cloudflare/partykit#443 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 62/100
cloudflare/partykit#434 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 69/100
cloudflare/partykit#429 ·
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
cloudflare/partykit#428 ·
All issues in cloudflare/partykit
Similar issues
-
bug parity
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
WenyuChiou/agent-board#1489 ·
Maintainers usually reply within 1 day
-
area: bazaar bug complexity: medium
Difficulty 2/5 1-3 hours Newbie friendliness 74/100
accensa/x402-facilitator-stellar#779 ·
Maintainers usually reply within 1 day
-
bug good first issue P4 size:S web-ui
Difficulty 2/5 Half a day Newbie friendliness 85/100
josephfung/curia#2600 ·
Maintainers usually reply within 1 day