block/buzz · error · IngestError::Rejected

channel not found

Error message

channel not found

What it means

get_channel() for the h-tag UUID failed and the error is mapped to "channel not found" — the UUID does not resolve to a channel in this community (and note the map_err also folds genuine DB failures into this message). Admin-event validation happens before storage, so the mutation is rejected up front. Cross-community UUIDs never resolve because the lookup is fenced to tenant.community().

Source

Thrown at crates/buzz-relay/src/handlers/side_effects.rs:328

) -> anyhow::Result<()> {
    // CREATE_GROUP doesn't need an existing channel — skip h-tag extraction
    if kind == 9007 {
        return Ok(());
    }

    // Extract channel from h tag
    let channel_id =
        extract_h_tag_channel(event).ok_or_else(|| anyhow::anyhow!("missing or invalid h tag"))?;

    let actor_bytes = event.pubkey.to_bytes().to_vec();

    // Reject mutations on archived channels — except kind:9002 with archived=false
    // (unarchive), which must be allowed through so the channel can be restored.
    let channel = state
        .db
        .get_channel(tenant.community(), channel_id)
        .await
        .map_err(|_| anyhow::anyhow!("channel not found"))?;
    let is_unarchive_request = kind == 9002
        && event.tags.iter().any(|t| {
            let parts = t.as_slice();
            parts.len() >= 2 && parts[0] == "archived" && parts[1] == "false"
        });
    if channel.archived_at.is_some() && !is_unarchive_request {
        return Err(anyhow::anyhow!("channel is archived"));
    }

    match kind {
        9000 => {
            // An absent role tag means "no role change requested": for an existing
            // member that preserves the role they already hold, and only defaults
            // to Member for a genuinely new member. Defaulting unconditionally to
            // Member made a bare self-targeted PUT_USER silently demote an owner.
            let role_str = extract_tag_value(event, "role");
            let requested_role = match role_str {
                Some(ref s) => match s.parse::<buzz_db::channel::MemberRole>() {

View on GitHub (pinned to f956e6fe06)

Solutions

  1. Re-list channels for the community and copy the exact UUID into the h tag
  2. If the channel was deleted, recreate it (kind 9007) before issuing further admin events
  3. Check relay logs/DB health — a real database error is reported through this same message, so verify connectivity before assuming the UUID is wrong
  4. In tests, create the channel first and use the returned id, never a fabricated UUID

Example fix

// before: fabricated/stale UUID
let h = "00000000-0000-0000-0000-000000000000".to_string();

// after: resolve the real channel id
let channels = client.get_channels().await?;
let h = channels.iter().find(|c| c.name == "general").unwrap().id.to_string();
Defensive patterns

Strategy: validation

Validate before calling

// Confirm the channel exists in this community before mutating it
let channel = client.get_channel(community, channel_uuid).await;
match channel {
    Ok(ch) => ch,
    Err(_) => anyhow::bail!("channel {channel_uuid} not found — refresh channel list"),
}

Try / catch

match validate_admin_event(&tenant, kind, &event, &state).await {
    Err(e) if e.to_string().contains("channel not found") => {
        // Do not retry with the same UUID; refresh the channel list and re-target.
        // Also check DB health — real DB errors surface through this same message.
        refresh_channels_and_abort(&event)
    }
    other => other,
}

Prevention

When it happens

Trigger: h tag carries a UUID from a different community/relay or a stale/deleted channel; UUID typo (swapped digits still parse but match nothing); the channel was hard-deleted after a kind 9008 delete; the database is unreachable and the DB error is masked as not-found.

Common situations: Copied channel UUID from another environment (staging → prod); client cached an old channel list; concurrent delete racing a later admin event; using a random/generated UUID in tests without creating the channel first.

Related errors


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