zed-industries/zed · error · Error::Internal
can't delete channel while a call is in progress
Error message
can't delete channel while a call is in progress
What it means
Thrown by delete_channel when any room under the channel (or any of its descendant channels collected into channels_to_remove) still has rows in room_participant (crates/collab/src/db/queries/channels.rs:263-272). The count query inner-joins room on ChannelId, so a single active participant anywhere in the subtree blocks the whole deletion inside the transaction.
Source
Thrown at crates/collab/src/db/queries/channels.rs:272
.await?;
let channels_to_remove = self
.get_channel_descendants_excluding_self([&channel], &tx)
.await?
.into_iter()
.map(|channel| channel.id)
.chain(Some(channel_id))
.collect::<Vec<_>>();
let channel_has_active_participants = room_participant::Entity::find()
.inner_join(room::Entity)
.filter(room::Column::ChannelId.is_in(channels_to_remove.iter().copied()))
.count(&*tx)
.await?
> 0;
if channel_has_active_participants {
Err(anyhow!("can't delete channel while a call is in progress"))?;
}
channel::Entity::delete_many()
.filter(channel::Column::Id.is_in(channels_to_remove.iter().copied()))
.exec(&*tx)
.await?;
Ok((channel.root_id(), channels_to_remove))
})
.await
}
/// Invites a user to a channel as a member.
pub async fn invite_channel_member(
&self,
channel_id: ChannelId,
invitee_id: UserId,
inviter_id: UserId,View on GitHub (pinned to bc538def45)
Solutions
- Have all participants leave the call (or kick them) so room_participant rows for those rooms are deleted, then retry the channel deletion
- Check for orphaned room_participant rows (participants whose connection is gone) and clean them up before retrying
- If deleting a channel tree, ensure no child channel's room has participants either — the check covers the whole channels_to_remove set
Defensive patterns
Strategy: validation
Validate before calling
// Before delete_channel: confirm no room under the subtree has participants
let busy = rooms_under_channel_subtree
.iter()
.any(|room| room.active_participants > 0);
if busy {
return Err(anyhow!("ask participants to leave the call before deleting"));
} Try / catch
match db.delete_channel(channel_id, admin_id).await {
Ok(result) => Ok(result),
Err(err) if err.to_string().contains("call is in progress") => {
// surface an actionable 'participants still in call' message to the admin UI
Err(anyhow!("channel busy: a call is still in progress"))
}
Err(err) => Err(err),
} Prevention
- Check for active room participants before offering channel deletion in admin UIs
- Kick remaining participants (or wait for their disconnect cleanup) before deleting
- Monitor for orphaned room_participant rows from crashed clients and reap them
When it happens
Trigger: Calling delete_channel (admin RPC) while one or more users are in a call room belonging to the channel or any of its child channels; a crashed client whose room_participant row was never cleaned up on disconnect.
Common situations: Admin deletes a busy channel during a scheduled cleanup; leftover room_participant rows from a server that missed a leave event; CI/integration tests deleting fixture channels without first closing the call rooms.
Related errors
- not a collaborator on this project
- channel name can't be blank
- no such invitation
- no such member
- user is not a channel admin or channel does not exist
AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16).
Data as JSON: /api/errors/1a773222c95e61be.
Report an issue: GitHub.