block/buzz · error

publish canonical role

Error message

publish canonical role

What it means

Panic from `db.replace_addressable_event(community, &fresh, Some(channel)).await.expect("publish canonical role")`. The test asserts that a fresh kind:39002 roster event (newer created_at) is accepted via last-write-wins (NIP-33 style) replacement; the expect fires when the DB call returns Err instead of the expected (result, replaced=true) tuple.

Source

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

        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")
        ));
        let live_id: Vec<u8> = sqlx::query_scalar(
            "SELECT id FROM events WHERE community_id=$1 AND channel_id=$2 \
             AND kind=39002 AND deleted_at IS NULL",
        )
        .bind(community_uuid)
        .bind(channel)

View on GitHub (pinned to dad5a33865)

Solutions

  1. Ensure TEST_DATABASE_URL points at a running Postgres with current migrations (just setup / just test).
  2. Check the scratch DB setup/teardown helpers in this test file — the community and channel rows must exist before publishing the roster.
  3. Confirm replace_addressable_event still accepts kind:39002 events with custom created_at after any LWW-related changes.
  4. Run with RUST_BACKTRACE=1 and the sqlx query log to see the underlying DB error.

Example fix

// before
assert!(db.replace_addressable_event(community, &fresh, Some(channel)).await.expect("publish canonical role").1);
// after
let res = db.replace_addressable_event(community, &fresh, Some(channel)).await
    .unwrap_or_else(|e| panic!("publish canonical role: {e:?}"));
assert!(res.1, "expected LWW replacement of existing roster");
Defensive patterns

Strategy: try-catch

Validate before calling

// before publishing, confirm prerequisites exist
let community_row = sqlx::query("SELECT 1 FROM communities WHERE id=$1").bind(community).fetch_optional(&pool).await.expect("check community");
assert!(community_row.is_some(), "community row must exist before roster publish");

Try / catch

match db.replace_addressable_event(community, &fresh, Some(channel)).await {
    Ok((_, true)) => {}, // replaced as expected
    Ok((_, false)) => panic!("fresh roster was not treated as LWW winner"),
    Err(e) => panic!("publish canonical role failed: {e}"),
}

Prevention

When it happens

Trigger: `replace_addressable_event` errors when the addressable event fails verification, the community/channel row does not exist, the scratch database schema/migrations are stale, or a database connection error occurs (TEST_DATABASE_URL unreachable).

Common situations: Running integration tests without Postgres provisioned, migrations not applied to the scratch DB, or a code change to replace_addressable_event that now rejects valid roster events.

Related errors


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