block/buzz · error

sign roster

Error message

sign roster

What it means

This panic message comes from `EventBuilder::sign_with_keys(...).expect("sign roster")` inside a test helper that builds a kind:39002 (community roster / membership) event signed with the relay keys. It fires when the builder cannot produce a signed Nostr event — almost always because the key material is invalid or a required tag/header is missing. The library throws it to fail the test immediately rather than return an untestable Result.

Source

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

        .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))
            .await
            .expect_err("desired-state fence must reject stale role");
        assert!(matches!(
            error,
            DbError::Sqlx(sqlx::Error::Database(ref db_error))
                if db_error.code().as_deref() == Some("23514")

View on GitHub (pinned to dad5a33865)

Solutions

  1. Check how `relay_keys` is constructed in this test file and confirm it holds valid KeyPair/Keys (e.g. Keys::generate() or a valid hex secret).
  2. Run the failing test with RUST_BACKTRACE=1 to see whether the panic originates in key parsing or in event signing.
  3. Verify the Tag::parse calls above it succeed — a bad tag list can leave the builder in a bad state; add distinct expect messages to isolate which call panics.
  4. If keys are loaded from env/config, validate them once in test setup and fall back to Keys::generate() for scratch tests.

Example fix

// before
let relay_keys = Keys::parse(env_key_hex).expect("relay keys");
// after
let relay_keys = match env_key_hex {
    Ok(h) => Keys::parse(h).expect("valid relay key hex"),
    Err(_) => Keys::generate(), // scratch test does not need a fixed key
};
Defensive patterns

Strategy: validation

Validate before calling

// validate keys before building/signing the roster event
let secret = relay_keys.secret_key().expect("relay keys have a secret key");
assert_eq!(secret.display_secret().len(), 64, "secret key must be 32-byte hex");

Type guard

fn has_signable_keys(keys: &Keys) -> bool {
    keys.secret_key().map(|s| s.display_secret().len() == 64).unwrap_or(false)
}

Prevention

When it happens

Trigger: Calling `sign_with_keys(&relay_keys)` on an EventBuilder whose keys cannot sign (malformed/empty SecretKey in `relay_keys`), or when event construction with `.tags([...]).custom_created_at(...)` produced an internally inconsistent event that signing rejects.

Common situations: Test fixtures where `relay_keys` was generated or parsed incorrectly (e.g. hex-decoded from an invalid string), refactors that changed EventBuilder tag APIs so a tag list is malformed, or deterministic-timestamp helpers constructing Timestamp::from(0) values rejected by validation.

Related errors


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