block/buzz · error
d tag
Error message
d tag
What it means
The test builds kind:39002 roster events and parses the channel d tag with Tag::parse(["d", channel.to_string()]). The expect panics when nostr's Tag::parse rejects the tag — the tag array is empty, or (for certain tag kinds) a required component like the pubkey/value is invalid. For d tags this usually means the value failed validation in the nostr crate version in use.
Source
Thrown at crates/buzz-db/src/store/channel_members.rs:3171
let owner = owner_keys.public_key().to_bytes();
seed_community_channel(&pool, community_uuid, channel, &owner_keys).await;
let member = Keys::generate().public_key().to_bytes();
sqlx::query(
"INSERT INTO channel_members (community_id, channel_id, pubkey, role, invited_by) \
VALUES ($1, $2, $3, 'admin', $4)",
)
.bind(community_uuid)
.bind(channel)
.bind(member.as_slice())
.bind(owner.as_slice())
.execute(&pool)
.await
.expect("seed canonical admin");
let roster = |role: &str, timestamp| {
EventBuilder::new(Kind::Custom(39002), "")
.tags(vec![
Tag::parse(["d", channel.to_string().as_str()]).expect("d tag"),
Tag::parse(["p", hex::encode(owner).as_str(), "", "owner"])
.expect("owner p tag"),
Tag::parse(["p", hex::encode(member).as_str(), "", role])
.expect("member p tag"),
])
.custom_created_at(Timestamp::from(timestamp))
.sign_with_keys(&relay_keys)
.expect("sign roster")
};
let base = Timestamp::now().as_secs();
let fresh = roster("admin", base);
assert!(
db.replace_addressable_event(community, &fresh, Some(channel))
.await
.expect("publish canonical role")
.1
);
let stale = roster("member", base + 1);View on GitHub (pinned to dad5a33865)
Solutions
- Print channel.to_string() to confirm it is a non-empty, expected-format value
- Check the nostr crate's Tag::parse docs/changelog for stricter validation in the pinned version
- Construct the tag directly (Tag::custom) if generic parsing is too strict for a valid test value
- Ensure `d tag` isn't shadowed by another binding in scope (see error 83's `slash` shadow note)
Example fix
// before
Tag::parse(["d", channel.to_string().as_str()]).expect("d tag"),
// after
let d_tag = Tag::parse(["d", channel.to_string().as_str()])
.unwrap_or_else(|e| panic!("d tag parse failed for '{}': {e}", channel)); Defensive patterns
Strategy: validation
Validate before calling
let d = channel.to_string(); assert!(!d.is_empty(), "d tag value must be non-empty");
Type guard
fn parseable_tag(parts: [&str; 2]) -> bool {
nostr::Tag::parse(parts).is_ok()
} Try / catch
let d_tag = Tag::parse(["d", channel.to_string().as_str()])
.unwrap_or_else(|e| panic!("d tag parse failed: {e}; nostr crate version compatibility?")); Prevention
- Pin and review the nostr crate version when tags fail to parse
- Prefer typed Tag constructors over generic Tag::parse
- Sanity-print tag values in test failures
When it happens
Trigger: Tag::parse returning Err for ["d", channel.to_string()] when channel.to_string() yields an empty or malformed value, or the nostr crate version validates d-tag values more strictly than the test anticipates.
Common situations: Upgrading the nostr crate changed Tag::parse validation (e.g. rejecting empty values or new length limits); passing a Uuid formatting that includes characters a version rejects; constructing the tag with wrong arity.
Related errors
- owner p tag
- member p tag
- moderation notice recipient must be a 32-byte pubkey, got {}
- failed to sign moderation notice: {e}
- failed to sign system message: {e}
AI-assisted analysis of block/buzz@dad5a33865 (2026-08-30).
Data as JSON: /api/errors/c24dfb54d1ad3b20.
Report an issue: GitHub.