zed-industries/zed · error · Error::Internal
user is not a channel participant or channel does not exist
Error message
user is not a channel participant or channel does not exist
What it means
Thrown by check_user_is_channel_participant (crates/collab/src/db/queries/channels.rs:784): the loosest of the three role checks — Admin, Member, Guest and Talker all pass; only Banned users and users with no membership row (None) are rejected.
Source
Thrown at crates/collab/src/db/queries/channels.rs:784
"user is not a channel member or channel does not exist"
))?,
}
}
/// Returns whether the given user is a participant in the specified channel.
pub async fn check_user_is_channel_participant(
&self,
channel: &channel::Model,
user_id: UserId,
tx: &DatabaseTransaction,
) -> Result<ChannelRole> {
let role = self.channel_role_for_user(channel, user_id, tx).await?;
match role {
Some(ChannelRole::Admin)
| Some(ChannelRole::Member)
| Some(ChannelRole::Guest)
| Some(ChannelRole::Talker) => Ok(role.unwrap()),
Some(ChannelRole::Banned) | None => Err(anyhow!(
"user is not a channel participant or channel does not exist"
))?,
}
}
/// Returns a user's pending invite for the given channel, if one exists.
pub async fn pending_invite_for_channel(
&self,
channel: &channel::Model,
user_id: UserId,
tx: &DatabaseTransaction,
) -> Result<Option<channel_member::Model>> {
let row = channel_member::Entity::find()
.filter(channel_member::Column::ChannelId.eq(channel.root_id()))
.filter(channel_member::Column::UserId.eq(user_id))
.filter(channel_member::Column::Accepted.eq(false))
.one(tx)
.await?;View on GitHub (pinned to bc538def45)
Solutions
- Ensure the user has joined the channel (a channel_member row exists) before issuing participant operations
- If banned, an admin must lift the ban (set role to Guest or higher) before the user can participate again
- Double-check the channel_id in the request — the None arm fires when the user simply isn't in that channel
Defensive patterns
Strategy: validation
Validate before calling
fn can_participate(role: Option<ChannelRole>) -> bool {
!matches!(role, None | Some(ChannelRole::Banned))
} Type guard
fn is_channel_participant(role: Option<ChannelRole>) -> bool {
!matches!(role, None | Some(ChannelRole::Banned))
} Prevention
- Require a channel_member row (any non-banned role) before participant operations
- On ban, immediately stop sending participant RPCs from the client
- Validate channel_id — a user absent from that channel falls into the None arm
When it happens
Trigger: A banned user attempting participant-level operations (reading/participating in the channel), or a user with no channel_member row at all (never joined, or membership fully removed) invoking a participant-gated RPC.
Common situations: Banned users with still-open clients continuing to send events; operations issued against the wrong channel_id where the user never joined; membership rows removed by an admin purge while sessions stayed alive.
Related errors
- user is not a channel admin or channel does not exist
- user is not a channel member or channel does not exist
- guests cannot share projects
- not authorized to edit projects
- not authorized to read projects
AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16).
Data as JSON: /api/errors/b8ec598f2e464885.
Report an issue: GitHub.