partyserver: with hibernation off, a client close without a status code (1005) is never answered, so the client stays in CLOSING
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 69/100
- Issue type
- Bug
- Clarity
- Clearly specified
- Activity status
- Active
- Tech stack
- typescript
- Domain
- networking
Research direction
Start by reading the closeQuietly implementation and the change in #394; the issue identifies the reserved close codes and gives a reproduction using hibernate: false. Reproduce the code-less close and check the socket state after 6 seconds, then verify that the client receives a Close frame and leaves CLOSING after the fix.
Written by the indexing model from the issue text.
Description
Since #394, closeQuietly skips the reply for the reserved codes 1005, 1006 and 1015. 1006 and 1015 mean that no Close frame arrived. 1005 does not: it is what the server reports when the client sent a real Close frame with an empty body, which is what ws.close() with no arguments does. The transport is still open, and the client waits in CLOSING for the server's Close frame.
On a non-hibernating server (static options = { hibernate: false }) that frame never comes. y-partyserver's provider calls ws.close() with no code in disconnect(), so every YProvider.disconnect() ends this way. The provider keeps wsconnected === true until the socket finally dies, and a connect() in the meantime does nothing.
The #394 notes say compatibility dates on or after 2026-04-07 auto-reply to Close frames. That does not happen for these sockets: the result below is on compatibility date 2026-11-01.
Repro (wrangler 4.159.0, workerd 1.20261109.1, partyserver 0.5.10, y-partyserver 2.2.0, compatibility date 2026-11-01, hibernate: false):
- Start a
YServersubclass withhibernate: false(for example viaunstable_startWorker). - Open a raw WebSocket to
/parties/<party>/<room>, wait foropen, then callws.close()with no code. - With the stock
onClose, the client is still in readyState 2 (CLOSING) after 6000 ms. - Add
if (code === 1005) connection.close(1000, 'Closed')toonClose. The close completes in 14 ms and the client sees 1000.
In our production Worker that reply has run on every pause, reload and tab close since 2026-11-09. wrangler tail during a test run (57 events) showed no exceptions and no Network connection lost rejections.
Suggested fix: in closeQuietly, skip the reply only for 1006 and 1015. For 1005, reply with ws.close() (no code) or with 1000. A peer that sent a code-less Close frame is still there to receive the answer.
- 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 82/100
cloudflare/partykit#430 ·
-
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