block/buzz · error · IngestError::Rejected
channel name is required
Error message
channel name is required
What it means
Thrown when a kind:9002 "name" tag value canonicalizes to an empty string via buzz_core::channel::canonical_channel_name. This catches names made entirely of characters that are display prefixes (e.g. "#", "##") which are stripped during canonicalization, leaving nothing. The check exists so a rename can never blank out a channel name.
Source
Thrown at crates/buzz-relay/src/handlers/side_effects.rs:540
}
None => {
return Err(anyhow::anyhow!("archived tag must have a value"));
}
}
}
}
// Validate channel names before storage. A name made entirely of
// display-prefix hashes becomes empty after canonicalization.
for t in event.tags.iter() {
if t.kind().to_string() == "name" {
match t.content() {
Some(v)
if !buzz_core::channel::canonical_channel_name(v)
.trim()
.is_empty() => {}
_ => {
return Err(anyhow::anyhow!("channel name is required"));
}
}
}
}
// Validate visibility values before storage.
for t in event.tags.iter() {
if t.kind().to_string() == "visibility" {
match t.content() {
Some("open") | Some("private") => {}
Some(v) => {
return Err(anyhow::anyhow!(
"invalid visibility value: {v} (must be \"open\" or \"private\")"
));
}
None => {
return Err(anyhow::anyhow!("visibility tag must have a value"));
}View on GitHub (pinned to f956e6fe06)
Solutions
- Send a name containing at least one non-prefix character, e.g. ["name", "general"] without the leading '#'.
- Trim and validate the input client-side: reject names whose canonical form is empty before publishing.
- If the intent was to leave the name unchanged, omit the name tag from the 9002 event.
Example fix
// before — UI prefixes '#' and user typed nothing but '#'
{ kind: 9002, tags: [["h", ch], ["name", `#${userInput}`]] } // userInput = "#" → "##"
// after
const raw = userInput.replace(/^#+/, "").trim();
if (raw) {
{ kind: 9002, tags: [["h", ch], ["name", raw]] };
} Defensive patterns
Strategy: validation
Validate before calling
// Mirror the relay's canonicalization before publishing a rename
function canonicalChannelName(raw: string): string {
return raw.replace(/^#+/, "").trim().toLowerCase().replace(/[\s_]+/g, "-").replace(/[^a-z0-9-]/g, "");
}
const canon = canonicalChannelName(nameInput);
if (!canon) throw new Error("Channel name is empty after removing display prefix");
const tags = [["h", channelId], ["name", nameInput.trim()]]; Type guard
function isNonEmptyChannelName(raw: string): boolean {
// names made only of display-prefix hashes canonicalize to empty
return raw.replace(/^#+/, "").trim().length > 0;
} Try / catch
try {
await sdk.publish(editEvent);
} catch (e) {
if (String(e).includes("channel name is required")) {
form.setError("name", "Name needs at least one non-# character");
} else throw e;
} Prevention
- Strip any leading '#' in the UI input before building the name tag — the relay stores canonical names.
- Disable the save button when the trimmed input is empty or only '#'.
- Omit the name tag entirely when the name field is unchanged.
When it happens
Trigger: Publishing [["name", "###"], ["name", ""], ["name", "#"]], or a name consisting only of whitespace/hash prefix characters in a kind:9002 event.
Common situations: UI passing an untrimmed input where the user typed only '#'; pre-pending '#' to channel names client-side and then sending names like '#general' where the user typed just '#'; renaming from a template variable that rendered empty.
Related errors
- kind:9002 must include at least one metadata tag (name, abou
- invalid archived value: {v} (must be "true" or "false")
- archived tag must have a value
- invalid visibility value: {v} (must be "open" or "private")
- visibility tag must have a value
AI-assisted analysis of block/buzz@f956e6fe06 (2026-08-16).
Data as JSON: /api/errors/4c0675ef7aaa649d.
Report an issue: GitHub.