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

  1. Ensure the user has joined the channel (a channel_member row exists) before issuing participant operations
  2. If banned, an admin must lift the ban (set role to Guest or higher) before the user can participate again
  3. 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

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


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