{"record":{"id":"debe0eaa114451f9","repo":"zed-industries/zed","slug":"badpublicnesting","errorCode":"BadPublicNesting","errorMessage":"BadPublicNesting","messagePattern":"BadPublicNesting","errorType":"error_code","errorClass":"RpcError","httpStatus":null,"severity":"error","filePath":"crates/collab/src/db/queries/channels.rs","lineNumber":936,"sourceCode":"            self.check_user_is_channel_admin(&channel, admin_id, &tx)\n                .await?;\n            let new_parent = self.get_channel_internal(new_parent_id, &tx).await?;\n\n            if new_parent.root_id() != channel.root_id() {\n                Err(anyhow!(ErrorCode::WrongMoveTarget))?;\n            }\n\n            if new_parent\n                .ancestors_including_self()\n                .any(|id| id == channel.id)\n            {\n                Err(anyhow!(ErrorCode::CircularNesting))?;\n            }\n\n            if channel.visibility == ChannelVisibility::Public\n                && new_parent.visibility != ChannelVisibility::Public\n            {\n                Err(anyhow!(ErrorCode::BadPublicNesting))?;\n            }\n\n            let root_id = channel.root_id();\n            let new_parent_path = new_parent.path();\n            let old_path = format!(\"{}{}/\", channel.parent_path, channel.id);\n            let new_path = format!(\"{}{}/\", new_parent_path, channel.id);\n            let new_order = max_order(&new_parent_path, &tx).await? + 1;\n\n            let mut model = channel.into_active_model();\n            model.parent_path = ActiveValue::Set(new_parent.path());\n            model.channel_order = ActiveValue::Set(new_order);\n            let channel = model.update(&*tx).await?;\n\n            let descendent_ids =\n                ChannelId::find_by_statement::<QueryIds>(Statement::from_sql_and_values(\n                    self.pool.get_database_backend(),\n                    \"\n                    UPDATE channels SET parent_path = REPLACE(parent_path, $1, $2)","sourceCodeStart":918,"sourceCodeEnd":954,"githubUrl":"https://github.com/zed-industries/zed/blob/bc538def4545534201bbfcac4e95ac34ea6501b6/crates/collab/src/db/queries/channels.rs#L918-L954","documentation":"ErrorCode::BadPublicNesting from move_channel (crates/collab/src/db/queries/channels.rs:936): the moved channel is public but the new parent is not public. A public channel must remain visible under public ancestors; placing it under a non-public parent would either leak it or break visibility rules, so the move is rejected.","triggerScenarios":"move_channel(channel_id, new_parent_id, admin_id) where channel.visibility == Public and new_parent.visibility != Public (e.g. dragging a public channel under a private parent).","commonSituations":"Org restructuring that mixes public and private subtrees; UI not displaying/badging visibility on drop targets, so admins unknowingly drop public under private.","solutions":["Flip the channel to private before the move, or pick a public new parent","Gate drop targets in the UI on visibility: only offer parents whose visibility is Public when the dragged channel is Public","If the intent is to hide the channel, change its visibility explicitly rather than nesting it under a private parent"],"exampleFix":"// before\nclient.move_channel(public_channel_id, private_parent_id, admin_id).await?;\n\n// after\nif channel.visibility == ChannelVisibility::Public {\n    assert_eq!(new_parent.visibility, ChannelVisibility::Public);\n}\nclient.move_channel(channel_id, new_parent_id, admin_id).await?;","handlingStrategy":"validation","validationCode":"// Public channels need a public parent\nif channel.visibility == ChannelVisibility::Public\n    && new_parent.visibility != ChannelVisibility::Public\n{\n    return Err(anyhow!(\"public channel requires a public parent\"));\n}","typeGuard":null,"tryCatchPattern":"match db.move_channel(channel_id, new_parent_id, admin_id).await {\n    Ok(v) => Ok(v),\n    Err(err) if err.to_string().contains(\"BadPublicNesting\") => {\n        Err(anyhow!(\"make the channel private or pick a public parent\"))\n    }\n    Err(err) => Err(err),\n}","preventionTips":["Badge channel and drop-target visibility in the UI so mismatches are visible","Filter drop targets by visibility whenever the dragged channel is public","Change visibility explicitly rather than via nesting tricks"],"tags":["collab","channels","tree","visibility"],"backgroundTag":null,"analyzedSha":"bc538def4545534201bbfcac4e95ac34ea6501b6","analyzedAt":"2026-08-16T07:30:46.435Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}