zed-industries/zed · error · Error::Internal

user is not a channel admin or channel does not exist

Error message

user is not a channel admin or channel does not exist

What it means

Thrown by check_user_is_channel_admin (crates/collab/src/db/queries/channels.rs:746): the user's ChannelRole resolved via channel_role_for_user is Member, Talker, Guest, Banned, or None (no membership row) — only Admin passes. Guards every admin-only operation (rename, delete, move, role changes).

Source

Thrown at crates/collab/src/db/queries/channels.rs:746

        })
        .await
    }

    /// Returns whether the given user is an admin in the specified channel.
    pub async fn check_user_is_channel_admin(
        &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) => Ok(role.unwrap()),
            Some(ChannelRole::Member)
            | Some(ChannelRole::Talker)
            | Some(ChannelRole::Banned)
            | Some(ChannelRole::Guest)
            | None => Err(anyhow!(
                "user is not a channel admin or channel does not exist"
            ))?,
        }
    }

    /// Returns whether the given user is a member of the specified channel.
    pub async fn check_user_is_channel_member(
        &self,
        channel: &channel::Model,
        user_id: UserId,
        tx: &DatabaseTransaction,
    ) -> Result<ChannelRole> {
        let channel_role = self.channel_role_for_user(channel, user_id, tx).await?;
        match channel_role {
            Some(ChannelRole::Admin) | Some(ChannelRole::Member) => Ok(channel_role.unwrap()),
            Some(ChannelRole::Banned)
            | Some(ChannelRole::Guest)
            | Some(ChannelRole::Talker)

View on GitHub (pinned to bc538def45)

Solutions

  1. Promote the user to ChannelRole::Admin for that channel before retrying (an existing admin must change the role)
  2. Ensure the client disables/hides admin actions based on the role delivered in membership_update events, and re-checks on role change
  3. Confirm you are passing the acting user's id (admin_id) and not the target's id — a swapped argument produces exactly this error
Defensive patterns

Strategy: validation

Validate before calling

// Client-side gate for admin actions
fn can_admin(role: Option<ChannelRole>) -> bool {
    matches!(role, Some(ChannelRole::Admin))
}

if !can_admin(my_role) {
    return Err(anyhow!("admin role required"));
}

Type guard

fn is_channel_admin(role: Option<ChannelRole>) -> bool {
    role == Some(ChannelRole::Admin)
}

Try / catch

match db.delete_channel(channel_id, admin_id).await {
    Ok(v) => Ok(v),
    Err(err) if err.to_string().contains("not a channel admin") => {
        Err(anyhow!("ask a channel admin to perform this action"))
    }
    Err(err) => Err(err),
}

Prevention

When it happens

Trigger: A non-admin member/guest/talker/banned user calling delete_channel, rename_channel, move_channel, or remove_channel_member; calling any of these after the user's admin role was downgraded; calling with a user id that has no channel_member row at all (None arm).

Common situations: Role downgraded while the client kept an admin UI visible; a guest granted Talker expecting admin rights; org admins (server-level) assuming channel-admin powers — server admin is a different flag and does not pass this check.

Related errors


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