{"record":{"id":"19a37cba3f1efba1","repo":"zed-industries/zed","slug":"channel-name-can-t-be-blank","errorCode":null,"errorMessage":"channel name can't be blank","messagePattern":"channel name can't be blank","errorType":"validation","errorClass":"Error::Internal","httpStatus":null,"severity":"error","filePath":"crates/collab/src/db/queries/channels.rs","lineNumber":339,"sourceCode":"                    true,\n                    &tx,\n                )\n                .await?\n                .into_iter()\n                .collect();\n\n            Ok(InviteMemberResult {\n                channel,\n                notifications,\n            })\n        })\n        .await\n    }\n\n    fn sanitize_channel_name(name: &str) -> Result<&str> {\n        let new_name = name.trim().trim_start_matches('#');\n        if new_name.is_empty() {\n            Err(anyhow!(\"channel name can't be blank\"))?;\n        }\n        Ok(new_name)\n    }\n\n    /// Renames the specified channel.\n    pub async fn rename_channel(\n        &self,\n        channel_id: ChannelId,\n        admin_id: UserId,\n        new_name: &str,\n    ) -> Result<channel::Model> {\n        self.transaction(move |tx| async move {\n            let new_name = Self::sanitize_channel_name(new_name)?.to_string();\n\n            let channel = self.get_channel_internal(channel_id, &tx).await?;\n            self.check_user_is_channel_admin(&channel, admin_id, &tx)\n                .await?;\n","sourceCodeStart":321,"sourceCodeEnd":357,"githubUrl":"https://github.com/zed-industries/zed/blob/bc538def4545534201bbfcac4e95ac34ea6501b6/crates/collab/src/db/queries/channels.rs#L321-L357","documentation":"Thrown by sanitize_channel_name (crates/collab/src/db/queries/channels.rs:339-344), the shared validator used by channel creation and rename. It trims whitespace and strips any leading '#' characters; if nothing remains, the name is blank and the operation is rejected before any DB write.","triggerScenarios":"Calling create_channel or rename_channel with a name of \"\", \"   \", \"#\", \"###\", or \"  #  \" — after trim + trim_start_matches('#') the string is empty. Only leading '#' is stripped, so \"a#b\" is fine but \"###\" is blank.","commonSituations":"Client UIs that don't validate before submitting; users entering only the channel prefix '#'; automated scripts importing channel lists that contain blank or prefix-only rows; mobile clients sending untrimmed input.","solutions":["Validate client-side with the same rule before sending the RPC: name.trim().trim_start_matches('#') must be non-empty","Send a name without the leading '#' (the server strips it anyway; sending '#' alone guarantees the error)","If importing channels, filter/repair blank entries in the import data first"],"exampleFix":"// before\nclient.send(CreateChannel { name: \"#\".into(), .. }).await?;\n\n// after\nfn is_valid_channel_name(name: &str) -> bool {\n    !name.trim().trim_start_matches('#').is_empty()\n}\nassert!(is_valid_channel_name(&name));\nclient.send(CreateChannel { name, .. }).await?;","handlingStrategy":"validation","validationCode":"fn sanitize_channel_name(name: &str) -> Option<&str> {\n    let trimmed = name.trim().trim_start_matches('#');\n    (!trimmed.is_empty()).then_some(trimmed)\n}\n\nif let Some(name) = sanitize_channel_name(&input) {\n    client.create_channel(name).await?;\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Apply the server's exact rule (trim + strip leading '#') in the client before submit","Disable the submit action while the sanitized name is empty","When bulk-importing channels, run the same sanitizer over the dataset first"],"tags":["collab","channels","validation"],"backgroundTag":null,"analyzedSha":"bc538def4545534201bbfcac4e95ac34ea6501b6","analyzedAt":"2026-08-16T07:30:46.435Z","schemaVersion":2},"datasetVersion":"2026-08-16T08:17:34.114Z"}