cloudflare / cloudflare/partykit
[y-partyserver] Awareness state is not sent to a client that joins an occupied room
- Dominant language
- TypeScript
- Stars
- 1.3k
- Forks
- 79
- PR merge metrics
- No merged PRs in 30d
Description
### What happens
When a client connects to a `YServer` room that already has other clients in it, the
newcomer receives the **document** state but never the **awareness** state of the
clients that were already connected. It only learns about them once one of them
happens to broadcast an awareness update.
The reverse direction works: the clients that were already connected do receive the
newcomer's awareness as soon as it joins.
The practical symptom is that a presence UI (avatars, remote carets) is empty for
whoever joins last, while everyone else can see them.
### Expected
On connect, the server sends the current awareness states of the room to the new
connection, as `y-websocket`'s reference server does — otherwise presence is only
eventually consistent, and only if someone moves.
### Reproduction
1. `YServer` room with two browser clients, `disableBc: true` on both so only the
server relays (with BroadcastChannel on, same-browser tabs mask the problem).
2. Client A connects and calls `awareness.setLocalStateField('user', { … })`.
3. Client B connects some seconds later and does the same.
```js
// Client B, after `status === 'connected'` and after the document has synced:
provider.awareness.getStates()
// → only B's own client id. A is missing.
// Client A at the same moment:
provider.awareness.getStates()
// → both A and B.
```
### Evidence it is specific to awareness
On client B the connection is up and the document arrives over that same socket —
the editor renders the room's content — so this is not a connection or auth problem.
It is only the awareness state that is not replayed.
### Workaround
Have each client re-broadcast its own awareness whenever it notices a client id it
has not seen before. It settles after one round, but it means every client needs
this, and presence is briefly wrong before it does.
```js
if (someClientIdIsNew) provider.awareness.setLocalStateField('user', me)
```
### Versions
- `y-partyserver` 2.2.0
- `partyserver` 0.5.10
- `yjs` 13.6.32
- Durable Objects, SQLite storage, `hibernate: true`, `workerd` 1.20260826.1
Contributor guide
Research direction
Start by tracing YServer's connection and awareness relay handling, then compare the join behavior with y-websocket's reference server. Reproduce the issue with two clients using disableBc: true and verify that the later client receives the existing clients' awareness states immediately after connecting; the presence state should no longer depend on a later awareness broadcast.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- distributed-systems
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 68/100