zed-industries/zed · error
room does not exist or was already joined
Error message
room does not exist or was already joined
What it means
Thrown by join_room when the UPDATE that fills in participant_index and answering_connection_id on the pending room_participant row affects zero rows. That row is created by call(); if it no longer matches, the invitation is no longer open: the caller cancelled, the ring timed out, or the row was already answered (possibly by another connection of the same user).
Source
Thrown at crates/collab/src/db/queries/rooms.rs:342
.filter(
Condition::all()
.add(room_participant::Column::RoomId.eq(room_id))
.add(room_participant::Column::UserId.eq(user_id))
.add(room_participant::Column::AnsweringConnectionId.is_null()),
)
.set(room_participant::ActiveModel {
participant_index: ActiveValue::Set(Some(participant_index)),
answering_connection_id: ActiveValue::set(Some(connection.id as i32)),
answering_connection_server_id: ActiveValue::set(Some(ServerId(
connection.owner_id as i32,
))),
answering_connection_lost: ActiveValue::set(false),
..Default::default()
})
.exec(&*tx)
.await?;
if result.rows_affected == 0 {
Err(anyhow!("room does not exist or was already joined"))?;
}
let room = self.get_room(room_id, &tx).await?;
Ok(JoinRoom {
room,
channel: None,
})
})
.await
}
pub async fn stale_room_connection(&self, user_id: UserId) -> Result<Option<ConnectionId>> {
self.transaction(|tx| async move {
let participant = room_participant::Entity::find()
.filter(room_participant::Column::UserId.eq(user_id))
.one(&*tx)
.await?;
Ok(participant.and_then(|p| p.answering_connection()))View on GitHub (pinned to bc538def45)
Solutions
- Handle this error by telling the user the call ended and dropping the incoming-call state; offer to call back
- Ensure only one connection of the called user answers a given ring (pick one device, ignore the others)
- Refresh room state (get_room / room_updated events) after this failure so the UI resynchronizes
Example fix
// before
let join = client.join_room(room_id, connection_id).await?;
// after (recover from a dead ring)
let join = match client.join_room(room_id, connection_id).await {
Ok(join) => join,
Err(err) if err.to_string().contains("room does not exist or was already joined") => {
self.incoming_calls.remove(&room_id);
self.ui.show_toast("Call was cancelled or already answered");
return Ok(());
}
Err(err) => return Err(err),
}; Defensive patterns
Strategy: fallback
Validate before calling
// Only answer rings that are still live and not answered elsewhere.
if let Some(ring) = self.incoming_calls.get(&room_id) {
if ring.connection_id == my_connection_id && !ring.answered {
client.join_room(room_id, my_connection_id).await?;
return Ok(());
}
}
log::debug!("not answering stale ring for room {room_id}"); Try / catch
match client.join_room(room_id, my_connection_id).await {
Ok(join) => Ok(Some(join)),
Err(err) if err.to_string().contains("room does not exist or was already joined") => {
self.incoming_calls.remove(&room_id);
self.ui.show_toast("Call was cancelled or already answered");
Ok(None) // graceful fallback
}
Err(err) => Err(err),
} Prevention
- Answer a ring from exactly one connection/device
- Drop incoming-call state when cancel events arrive; never join a dead ring
- After this failure, resync room state before offering any retry
When it happens
Trigger: Answering a ring with JoinRoom after the caller hit cancel; answering after the ring expiry cleanup removed the row; two devices of the called user answer simultaneously and the second UPDATE matches nothing; answering a ring from a room you were since removed from.
Common situations: Slow user reaction to an incoming call notification; notification shown on two devices; network latency delivering the join after the caller hung up.
Related errors
- could not find call to decline
- banned users cannot invite
- could not update room participant location
- could not update room participant role
- no such project
AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16).
Data as JSON: /api/errors/f8d3b2a60aa04f62.
Report an issue: GitHub.