block/buzz · error · anyhow::Error

failed to sign kind:13534: {e}

Error message

failed to sign kind:13534: {e}

What it means

After the member tags are assembled, buzz-admin signs the kind:13534 membership-list event with the relay keypair via EventBuilder::sign_with_keys. Signing fails if the nostr crate cannot serialize the event — a tag that fails standardization, or a custom_created_at outside the accepted u64-seconds range — or if the keypair itself is unusable. Note the timestamp is computed as (existing + 1).max(now); a garbage stored created_at (e.g., milliseconds instead of seconds) overflows on the +1.

Source

Thrown at crates/buzz-admin/src/main.rs:374

    };

    let members = db.list_relay_members(tenant.community()).await?;

    let mut tags: Vec<Tag> = Vec::with_capacity(members.len() + 1);
    // NIP-70 protected-event marker — prevents re-broadcasting by third parties.
    tags.push(Tag::parse(["-"]).map_err(|e| anyhow::anyhow!("failed to build '-' tag: {e}"))?);
    for member in &members {
        tags.push(
            Tag::parse(["member", &member.pubkey, &member.role])
                .map_err(|e| anyhow::anyhow!("failed to build member tag: {e}"))?,
        );
    }

    let event = EventBuilder::new(Kind::Custom(KIND_NIP43_MEMBERSHIP_LIST as u16), "")
        .tags(tags)
        .custom_created_at(nostr::Timestamp::from(ts))
        .sign_with_keys(relay_keypair)
        .map_err(|e| anyhow::anyhow!("failed to sign kind:13534: {e}"))?;

    let (stored, was_inserted) = db
        .replace_addressable_event(tenant.community(), &event, None)
        .await?;
    if was_inserted {
        // Publish to Redis so live clients receive the updated roster.
        // Community-global scope (EventTopic::Global) matches the relay's own
        // membership-list publish path; the tenant fixes the community.
        if let Err(e) = pubsub
            .publish_event(tenant, EventTopic::Global, &stored.event)
            .await
        {
            warn!("Redis publish of kind:13534 failed: {e}");
        }
    }

    tracing::info!(
        member_count = members.len(),

View on GitHub (pinned to dad5a33865)

Solutions

  1. Read the chained {e} from the message first — it names the exact nostr Error variant (timestamp, key, or tag).
  2. Check the stored timestamp: SELECT created_at FROM events WHERE kind = 13534; — it must be Unix seconds, not milliseconds; fix the row.
  3. Confirm BUZZ_RELAY_PRIVATE_KEY is the relay's 32-byte hex or nsec secret (not the public key) with no whitespace or quotes.
  4. Re-run add-member/remove-member to rebuild and republish the list.

Example fix

-- before: created_at stored in milliseconds
SELECT created_at FROM events WHERE kind = 13534; -- 1737000000000
-- after: seconds
UPDATE events SET created_at = created_at / 1000 WHERE kind = 13534 AND created_at > 100000000000;
Defensive patterns

Strategy: validation

Validate before calling

-- before republishing kind:13534, confirm the previous created_at is sane Unix seconds
SELECT created_at FROM events WHERE kind = 13534;
-- valid seconds are < 10^11; anything ~1.7e12 is milliseconds and must be fixed

Try / catch

match run_publish_membership(...).await {
    Ok(_) => {},
    Err(e) if e.to_string().contains("failed to sign kind:13534") => {
        // inspect e.source() chain for the nostr Error variant before retrying;
        // do not blind-retry: signing failures are deterministic
        log_and_alert(&e);
    }
    Err(e) => return Err(e),
}

Prevention

When it happens

Trigger: The previous kind:13534 row's created_at was stored in milliseconds (1.7e12) so existing+1 leaves the valid seconds range; or the BUZZ_RELAY_PRIVATE_KEY parsed into a Keys object that cannot sign (wrong-length material); or one of the member tags serializes to an invalid form.

Common situations: Migrating timestamps between ms and s conventions; switching the relay key without updating the CLI env; a hand-edited membership event row.

Related errors


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