zed-industries/zed · error

not a room participant

Error message

not a room participant

What it means

Thrown by room_connection_ids when, after scanning all room_participant rows, the calling connection_id does not match any participant's answering_connection. The function both collects the other participants' connection ids and asserts membership; if this connection has no answering connection registered in the room, the caller is not an active participant.

Source

Thrown at crates/collab/src/db/queries/rooms.rs:1304

                .filter(room_participant::Column::RoomId.eq(room_id))
                .stream(&*tx)
                .await?;

            let mut is_participant = false;
            let mut connection_ids = HashSet::default();
            while let Some(participant) = participants.next().await {
                let participant = participant?;
                if let Some(answering_connection) = participant.answering_connection() {
                    if answering_connection == connection_id {
                        is_participant = true;
                    } else {
                        connection_ids.insert(answering_connection);
                    }
                }
            }

            if !is_participant {
                Err(anyhow!("not a room participant"))?;
            }

            Ok(connection_ids)
        })
        .await
    }

    async fn get_channel_room(
        &self,
        room_id: RoomId,
        tx: &DatabaseTransaction,
    ) -> Result<(Option<channel::Model>, proto::Room)> {
        let db_room = room::Entity::find_by_id(room_id)
            .one(tx)
            .await?
            .context("could not find room")?;

        let mut db_participants = db_room

View on GitHub (pinned to bc538def45)

Solutions

  1. Ensure the connection issuing room operations is the one that joined (answered) the room; rejoin the room from this connection first
  2. Wait for the join_room/rejoin_room response before sending further room-scoped requests on that connection
  3. On reconnect, invalidate room membership state and re-establish it before any dependent RPC

Example fix

// before
let peers = client.room_connection_ids(room_id, connection_id).await?;

// after (verify membership first)
if !self.joined_rooms.contains(&room_id) {
    client.join_room(room_id, connection_id).await?;
    self.joined_rooms.insert(room_id);
}
let peers = client.room_connection_ids(room_id, connection_id).await?;
Defensive patterns

Strategy: validation

Validate before calling

// Ensure this connection is an active participant before room-scoped calls.
if !self.joined_rooms.contains(&room_id) {
    client.join_room(room_id, my_connection_id).await?;
    self.joined_rooms.insert(room_id);
}
let peers = client.room_connection_ids(room_id, my_connection_id).await?;

Try / catch

match client.room_connection_ids(room_id, my_connection_id).await {
    Ok(ids) => Ok(ids),
    Err(err) if err.to_string().contains("not a room participant") => {
        client.join_room(room_id, my_connection_id).await?; // rejoin then retry once
        client.room_connection_ids(room_id, my_connection_id).await
    }
    Err(err) => Err(err),
}

Prevention

When it happens

Trigger: Issuing a room-scoped RPC that resolves other participants (e.g. room messaging/leaving flows) from a connection that never called join_room or whose answering_connection is still null (pending ring not yet answered); the same user participating from another connection/device; reconnected with a new ConnectionId without rejoining.

Common situations: Multi-device usage where one window joined the room but another issues the room operation; reconnect logic that reuses old room state with a fresh connection; acting on a room before the join handshake completes.

Related errors


AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16). Data as JSON: /api/errors/3cb523d56a1a269a. Report an issue: GitHub.