cloudflare / cloudflare/partykit

[y-partyserver] Awareness state is not sent to a client that joins an occupied room

Open
#420 0 comments 0 reactions 0 assignees View on GitHub
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

Open the contributing 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.