block/buzz · error · IngestError::Rejected

missing e tag for target event

Error message

missing e tag for target event

What it means

Thrown by kind:9005 (DELETE_EVENT) when no e tag with a hex-decodable event id can be found. The extractor find_maps over tags for kind "e" whose content hex-decodes successfully — so both a missing e tag and an e tag whose value is not valid hex (wrong length, non-hex characters) produce this error.

Source

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

        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 {
                        None
                    }
                })
                .ok_or_else(|| anyhow::anyhow!("missing e tag for target event"))?;

            // Verify the target event exists and belongs to the h-tag channel
            // BEFORE storage. Fail closed: missing target → reject.
            let target_event = state
                .db
                .get_event_by_id(tenant.community(), &target_id)
                .await
                .map_err(|e| anyhow::anyhow!("db error looking up target: {e}"))?
                .ok_or_else(|| anyhow::anyhow!("target event not found"))?;

            match target_event.channel_id {
                Some(target_ch) if target_ch != channel_id => {
                    return Err(anyhow::anyhow!(
                        "target event belongs to a different channel"
                    ));
                }
                None => {
                    return Err(anyhow::anyhow!("target event has no channel"));

View on GitHub (pinned to f956e6fe06)

Solutions

  1. Include ["e", <64-char lowercase hex event id>] of the message you want deleted.
  2. Convert note1... identifiers to hex before publishing (bech32 decode).
  3. Verify the id length is exactly 64 hex characters with no 0x prefix or whitespace.
  4. Confirm you are deleting a message id, not a channel uuid or a user pubkey.

Example fix

// before — bech32 id or missing e tag
{ kind: 9005, tags: [["h", ch], ["action_id", uuid]] }              // no e tag
{ kind: 9005, tags: [["h", ch], ["e", "note1qyq..."]] }          // not hex

// after
{ kind: 9005, tags: [["h", ch], ["e", hexEventId]] } // hexEventId = 64 hex chars
Defensive patterns

Strategy: validation

Validate before calling

const HEX64_RE = /^[0-9a-f]{64}$/;

function targetTag(eventId: string): string[] {
  const hex = eventId.startsWith("note1") ? bech32ToHex(eventId) : eventId;
  if (!HEX64_RE.test(hex)) throw new Error("Target event id must be 64 hex chars (convert note1... ids first)");
  return ["e", hex];
}

Type guard

function isHexEventId(v: string): boolean {
  return /^[0-9a-fA-F]{64}$/.test(v.trim());
}

Try / catch

try {
  await sdk.publish(deleteEvent);
} catch (e) {
  if (String(e).includes("missing e tag for target event")) {
    throw new Error("No valid [\"e\", <64-char hex id\"] tag on the delete event");
  } else throw e;
}

Prevention

When it happens

Trigger: Publishing kind:9005 without an e tag at all, or with [["e", "not-a-hex-id"], ["e", "zzzz"]] or an id with the 0x prefix. Only the first decodable e tag is used; an id that is a bech32 (note1...) encoding will also fail hex decoding.

Common situations: Passing a note1.../npub-style identifier where the relay expects 64-char hex; URL-decoding a deep link id incompletely; SDK field mix-ups sending the channel id in the e tag; truncation of the 64-char id by log/UI layers.

Related errors


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