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
- Assert owner.len() == 32 before building the tag and print hex::encode(owner) on failure
- Check the nostr crate version's Tag::parse p-tag rules; adjust the empty "" element if the version rejects it
- Use a Keys::generate().public_key() derived owner so the bytes are guaranteed valid
- 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
- Derive test pubkeys from Keys::generate() rather than hand-built buffers
- Verify byte length before hex encoding into tags
- Note crate versions that reject empty relay-hint elements
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
- d 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/b0b0e01aa550c05a.
Report an issue: GitHub.