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
- Choose a new parent within the same root tree (verify both channels' root_id() match client-side before issuing the move)
- Refresh the channel tree from the server before offering move targets, so cross-root targets are not shown
- 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
- Compare root_id() of dragged channel and drop target before offering the move
- Only present drop targets from the current root's tree in the UI
- Refresh the tree after every successful move so cached roots stay accurate
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
- channel name can't be blank
- CircularNesting
- BadPublicNesting
- can't delete channel while a call is in progress
- no such invitation
AI-assisted analysis of zed-industries/zed@bc538def45 (2026-08-16).
Data as JSON: /api/errors/7ce2bbe84b6401b5.
Report an issue: GitHub.