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

no such member

Error message

no such member

What it means

Thrown by remove_channel_member (crates/collab/src/db/queries/channels.rs:490) when the DELETE of the channel_member row for (channel_id, member_id) affects 0 rows — the target user has no membership row in that channel, whether never a member or already removed.

Source

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

        self.transaction(|tx| async move {
            let channel = self.get_channel_internal(channel_id, &tx).await?;

            if member_id != admin_id {
                self.check_user_is_channel_admin(&channel, admin_id, &tx)
                    .await?;
            }

            let result = channel_member::Entity::delete_many()
                .filter(
                    channel_member::Column::ChannelId
                        .eq(channel_id)
                        .and(channel_member::Column::UserId.eq(member_id)),
                )
                .exec(&*tx)
                .await?;

            if result.rows_affected == 0 {
                Err(anyhow!("no such member"))?;
            }

            Ok(RemoveChannelMemberResult {
                membership_update: self
                    .calculate_membership_updated(&channel, member_id, &tx)
                    .await?,
                notification_id: self
                    .remove_notification(
                        member_id,
                        rpc::Notification::ChannelInvitation {
                            channel_id: channel_id.to_proto(),
                            channel_name: Default::default(),
                            inviter_id: Default::default(),
                        },
                        &tx,
                    )
                    .await?,
            })

View on GitHub (pinned to bc538def45)

Solutions

  1. Refresh the member list from the latest membership_update notification before offering the remove action
  2. Treat the error as benign when the member is already gone (idempotent removal) and drop the notification cleanup accordingly
  3. Verify the member_id being sent is the one from the roster entry, not a user id from another context
Defensive patterns

Strategy: validation

Validate before calling

// Verify membership before issuing the kick
if channel_members.contains_key(&member_id) {
    db.remove_channel_member(channel_id, member_id, admin_id).await?;
}

Try / catch

// Kicking an already-gone member is a no-op
match db.remove_channel_member(channel_id, member_id, admin_id).await {
    Ok(result) => Ok(Some(result)),
    Err(err) if err.to_string().contains("no such member") => Ok(None),
    Err(err) => Err(err),
}

Prevention

When it happens

Trigger: Admin calls remove-member for a user who already left the channel; removing a user whose invitation was revoked (pending row deleted); two admins racing to kick the same member; client UI showing a stale member list.

Common situations: Stale channel roster in the client after a membership_update event was dropped; kick + auto-leave racing; retry of a remove that already succeeded.

Related errors


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