block/buzz · error

owner p tag

Error message

owner p tag

What it means

The test parses the owner membership p tag with Tag::parse(["p", hex::encode(owner), "", "owner"]). The expect panics when nostr's Tag::parse rejects it: p tags require a valid 32-byte hex pubkey as the second element; an empty recommended-relay element or non-hex/short pubkey fails validation.

Source

Thrown at crates/buzz-db/src/store/channel_members.rs:3173

        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);
        let error = db
            .replace_addressable_event(community, &stale, Some(channel))

View on GitHub (pinned to dad5a33865)

Solutions

  1. Assert owner.len() == 32 before building the tag and print hex::encode(owner) on failure
  2. Check the nostr crate version's Tag::parse p-tag rules; adjust the empty "" element if the version rejects it
  3. Use a Keys::generate().public_key() derived owner so the bytes are guaranteed valid
  4. Prefer Tag::public_key(owner_pubkey) constructors over raw parse where available

Example fix

// before
Tag::parse(["p", hex::encode(owner).as_str(), "", "owner"]).expect("owner p tag"),
// after
assert_eq!(owner.len(), 32, "owner pubkey must be 32 bytes");
Tag::parse(["p", hex::encode(owner).as_str(), "", "owner"]).expect("owner p tag"),
Defensive patterns

Strategy: validation

Validate before calling

assert_eq!(owner.len(), 32, "p-tag pubkey must be 32 bytes");
assert_eq!(hex::encode(owner).len(), 64);

Type guard

fn valid_p_tag(pubkey: &[u8]) -> bool {
    pubkey.len() == 32 && Tag::parse(["p", &hex::encode(pubkey), "", ""]).is_ok()
}

Try / catch

let tag = Tag::parse(["p", hex::encode(owner).as_str(), "", "owner"])
    .unwrap_or_else(|e| panic!("owner p tag invalid (owner={}): {e}", hex::encode(owner)));

Prevention

When it happens

Trigger: Tag::parse(["p", hex, "", role]) errors when `owner` is not exactly 32 bytes, hex encoding produces wrong length, or the nostr crate enforces p-tag pubkey validity (some versions reject empty third elements or validate the key).

Common situations: owner slice built from wrong-length bytes (e.g. truncated hash); crate upgrade tightened p-tag validation to reject empty relay hints; owner accidentally initialized to a zeroed/empty buffer.

Related errors


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