block/buzz · error · IngestError::Rejected
not a member
Error message
not a member
What it means
Thrown by kind:9002 when the event only carries topic/purpose tags (no privileged tags) and the actor is not a channel member. Topic and purpose edits are the most permissive metadata change — any active member may do them — but non-members may not, and unlike the privileged-tag branch there is no agent-owner fallback.
Source
Thrown at crates/buzz-relay/src/handlers/side_effects.rs:626
)
.await?
{
return Ok(());
}
Err(anyhow::anyhow!(
"actor not authorized for name/about/archived/visibility/ttl changes"
))
}
}
} else {
// topic/purpose: any member
let is_member = state
.is_member_cached(tenant.community(), channel_id, &actor_bytes)
.await?;
if is_member {
Ok(())
} else {
Err(anyhow::anyhow!("not a member"))
}
}
}
9005 => {
// DELETE_EVENT: event author OR channel owner/admin.
if let Some(action_id) = extract_tag_value(event, "action_id") {
Uuid::parse_str(&action_id)
.map_err(|_| anyhow::anyhow!("invalid action_id tag"))?;
}
// Extract target event from e tag to check authorship.
let target_id = event
.tags
.iter()
.find_map(|tag| {
if tag.kind().to_string() == "e" {
tag.content().and_then(|v| hex::decode(v).ok())
} else {View on GitHub (pinned to f956e6fe06)
Solutions
- Join the channel (or get re-added) before editing topic/purpose.
- Verify the h tag channel id matches a channel you are currently in (buzz channels list).
- If you were removed intentionally, ask a member or admin to make the edit.
- Pre-check membership via the members query before publishing in automation.
Example fix
// before — non-member sets the topic
await sdk.editChannelMetadata(channelId, { topic: "Sprint 42" }); // → "not a member"
// after — join first, then edit
await sdk.joinChannel(channelId);
await sdk.editChannelMetadata(channelId, { topic: "Sprint 42" }); Defensive patterns
Strategy: validation
Validate before calling
// topic/purpose edits only need membership — check it first
const members = await buzz.channelsMembersList(channelId);
if (!members.some((m) => m.pubkey === myPubkey)) {
throw new Error("Join the channel before editing its topic/purpose");
}
await sdk.editChannelMetadata(channelId, { topic, purpose }); Type guard
function canEditTopicPurpose(members: { pubkey: string }[], pubkey: string): boolean {
return members.some((m) => m.pubkey === pubkey);
} Try / catch
try {
await sdk.editChannelMetadata(channelId, { topic });
} catch (e) {
if (String(e).includes("not a member")) {
ui.toast("You must be a member of this channel to edit its topic");
} else throw e;
} Prevention
- Hide topic/purpose edit affordances for channels the user is not a member of.
- Re-check membership when opening old channel views — removal revokes edit rights immediately.
- Bots should confirm join success before attempting metadata writes.
When it happens
Trigger: Publishing kind:9002 with tags like [["h", ch], ["topic", "..."]] using a key that has no membership row in the channel — someone who never joined, already left, or was removed.
Common situations: Bots attempting to set topics in channels they were never invited to; humans editing a topic after an admin removed them; stale channel ids after channel recreation so the membership lookup misses.
Related errors
- actor is not an active member
- actor not authorized for name/about/archived/visibility/ttl
- 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
AI-assisted analysis of block/buzz@f956e6fe06 (2026-08-16).
Data as JSON: /api/errors/5898dc6406c20fb8.
Report an issue: GitHub.