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, soView on GitHub (pinned to dad5a33865)
Solutions
- Add a `d` tag containing the repo identifier to the kind:30617 event and re-sign before publishing.
- Ensure the tag value matches [a-zA-Z0-9._-]{1,64} with no leading dots and no '..' so it passes validate_repo_id next.
- 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
- Always emit a `d` tag on kind:30617 per NIP-33 before signing.
- Use a typed event builder rather than raw tag arrays.
- Unit-test announcement builders for required tags.
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
- invalid repo identifier: must be [a-zA-Z0-9._-]{1,64}, no le
- project announcement is missing its address
- invalid URL {url:?}: {e}
- moderation notice recipient must be a 32-byte pubkey, got {}
- invalid BUZZ_RELAY_PRIVATE_KEY: {e}
AI-assisted analysis of block/buzz@dad5a33865 (2026-08-30).
Data as JSON: /api/errors/89aedd31ed184786.
Report an issue: GitHub.