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

  1. Join the channel (or get re-added) before editing topic/purpose.
  2. Verify the h tag channel id matches a channel you are currently in (buzz channels list).
  3. If you were removed intentionally, ask a member or admin to make the edit.
  4. 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

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


AI-assisted analysis of block/buzz@f956e6fe06 (2026-08-16). Data as JSON: /api/errors/5898dc6406c20fb8. Report an issue: GitHub.