block/buzz · error

kind:30617 missing d tag

Error message

kind:30617 missing d tag

What it means

handle_git_repo_announcement_inner processes kind:30617 git repo announcement events. NIP-33 parameterized replaceable events require a `d` tag as the replaceable identifier; extract_tag_value returns None when the event has no `d` tag, and this anyhow error is raised. The event cannot be processed without a repo identifier.

Source

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

#[cfg(test)]
#[derive(Default)]
pub(crate) struct GitRepoAnnouncementGate {
    pub(crate) reached: tokio::sync::Notify,
    pub(crate) resume: tokio::sync::Notify,
}

pub(crate) async fn handle_git_repo_announcement_inner(
    tenant: &TenantContext,
    event: &Event,
    state: &Arc<AppState>,
    hooks: &GitRepoAnnouncementHooks,
) -> anyhow::Result<()> {
    #[cfg(not(test))]
    let _ = hooks;
    // Extract repo identifier from d tag (required for NIP-33 parameterized replaceable events).
    let repo_id =
        extract_tag_value(event, "d").ok_or_else(|| anyhow::anyhow!("kind:30617 missing d tag"))?;

    if !validate_repo_id(&repo_id) {
        return Err(anyhow::anyhow!(
            "invalid repo identifier: must be [a-zA-Z0-9._-]{{1,64}}, no leading dots, no '..'"
        ));
    }

    let owner_hex = hex::encode(event.pubkey.to_bytes());

    // The relay holds no persistent per-repo disk state: runtime reads and
    // writes hydrate an ephemeral bare repo from object storage per request
    // (see `api::git::hydrate`). Announce only (1) reserves the repo name and
    // (2) seeds the empty-manifest pointer that makes the repo clone-able.
    //
    // The `git_repo_names` table (Postgres) is the relay's name registry,
    // keyed `(community_id, repo_id)`. It serves three jobs at once inside the
    // server-resolved community boundary:
    //   - uniqueness: `INSERT … ON CONFLICT DO NOTHING` is atomic, so

View on GitHub (pinned to dad5a33865)

Solutions

  1. Add a `d` tag containing the repo identifier to the kind:30617 event and re-sign before publishing.
  2. Ensure the tag value matches [a-zA-Z0-9._-]{1,64} with no leading dots and no '..' so it passes validate_repo_id next.
  3. Upgrade the publishing client to a version that emits NIP-33-compliant `d` tags for announcements.

Example fix

// before
tags: [["t", "myrepo"]],
// after
tags: [["d", "myrepo"], ["t", "myrepo"]],
Defensive patterns

Strategy: validation

Validate before calling

fn has_d_tag(tags: &[[String;2]]) -> bool {
    tags.iter().any(|t| t[0] == "d" && !t[1].is_empty())
}

Type guard

fn extract_valid_d<'a>(event: &'a Event) -> Option<&'a str> {
    event.tags.iter().find_map(|t| (t.kind().as_str() == "d")
        .then(|| t.content()).flatten().filter(|c| !c.is_empty()))
}

Try / catch

match handle_git_repo_announcement(&event).await {
    Err(e) if e.to_string().contains("missing d tag") => {
        return Err(anyhow!("client bug: kind:30617 requires a NIP-33 d tag"));
    }
    r => r,
}

Prevention

When it happens

Trigger: Publishing (or rebroadcasting) a kind:30617 event whose tags contain no `d` tag — e.g. a hand-crafted event, a client bug omitting the tag, or a tag spelled differently (case-sensitive) such as `D`.

Common situations: Custom git-sync tooling constructing announcements manually without NIP-33 `d`; older client versions predating the d-tag requirement; copy-pasted event templates where the d tag was stripped by JSON tooling.

Related errors


AI-assisted analysis of block/buzz@dad5a33865 (2026-08-30). Data as JSON: /api/errors/89aedd31ed184786. Report an issue: GitHub.