zed-industries/zed · error · RpcError

WrongMoveTarget

WrongMoveTarget

Error message

WrongMoveTarget

What it means

ErrorCode::WrongMoveTarget from move_channel (crates/collab/src/db/queries/channels.rs:923): the proposed new parent channel's root_id() differs from the moved channel's root_id(). Channels form trees per root (shared workspace); moving a channel across root trees is structurally illegal, so the move is rejected before path rewriting.

Source

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

        Ok(room_id)
    }

    /// Move a channel from one parent to another
    pub async fn move_channel(
        &self,
        channel_id: ChannelId,
        new_parent_id: ChannelId,
        admin_id: UserId,
    ) -> Result<(ChannelId, Vec<Channel>)> {
        self.transaction(|tx| async move {
            let channel = self.get_channel_internal(channel_id, &tx).await?;
            self.check_user_is_channel_admin(&channel, admin_id, &tx)
                .await?;
            let new_parent = self.get_channel_internal(new_parent_id, &tx).await?;

            if new_parent.root_id() != channel.root_id() {
                Err(anyhow!(ErrorCode::WrongMoveTarget))?;
            }

            if new_parent
                .ancestors_including_self()
                .any(|id| id == channel.id)
            {
                Err(anyhow!(ErrorCode::CircularNesting))?;
            }

            if channel.visibility == ChannelVisibility::Public
                && new_parent.visibility != ChannelVisibility::Public
            {
                Err(anyhow!(ErrorCode::BadPublicNesting))?;
            }

            let root_id = channel.root_id();
            let new_parent_path = new_parent.path();
            let old_path = format!("{}{}/", channel.parent_path, channel.id);

View on GitHub (pinned to bc538def45)

Solutions

  1. Choose a new parent within the same root tree (verify both channels' root_id() match client-side before issuing the move)
  2. Refresh the channel tree from the server before offering move targets, so cross-root targets are not shown
  3. If the channel genuinely must live in the other tree, create it there and move content instead — there is no supported cross-root move

Example fix

// before
client.move_channel(channel_id, other_root_child_id, admin_id).await?;

// after
assert_eq!(channel.root_id(), new_parent.root_id(), "cross-root move");
client.move_channel(channel_id, new_parent_id, admin_id).await?;
Defensive patterns

Strategy: validation

Validate before calling

// Reject cross-root moves before sending
if channel.root_id() != new_parent.root_id() {
    return Err(anyhow!("can only move within the same root channel"));
}
db.move_channel(channel_id, new_parent_id, admin_id).await?;

Try / catch

match db.move_channel(channel_id, new_parent_id, admin_id).await {
    Ok(v) => Ok(v),
    Err(err) if err.to_string().contains("WrongMoveTarget") => {
        Err(anyhow!("move target is in a different root channel"))
    }
    Err(err) => Err(err),
}

Prevention

When it happens

Trigger: Calling move_channel(channel_id, new_parent_id, admin_id) where new_parent lives in a different root channel — e.g. dragging a channel from one shared workspace tree into another organization's channel tree.

Common situations: UI drag-and-drop between top-level workspaces; client holding stale channel data after a channel was itself moved into another tree, so the cached parent path no longer matches the server's root computation.

Related errors


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