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

  1. Print channel.to_string() to confirm it is a non-empty, expected-format value
  2. Check the nostr crate's Tag::parse docs/changelog for stricter validation in the pinned version
  3. Construct the tag directly (Tag::custom) if generic parsing is too strict for a valid test value
  4. 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

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


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