block/buzz · error
failed to sign member snapshot: {error}
Error message
failed to sign member snapshot: {error} What it means
store_group_members_event builds the NIP-29 kind:39002 member snapshot event and signs it with the relay's own identity keypair via sign_with_keys. This error wraps any failure from the nostr signing operation, meaning the relay could not produce a valid signature over the snapshot event. It is a server-internal error — the snapshot was constructed but never signed or published.
Source
Thrown at crates/buzz-relay/src/handlers/side_effects.rs:1017
let ts = member_snapshot
.latest_member_event_timestamp(tenant.community(), channel_id, &relay_pubkey)
.await?
.map(|timestamp| timestamp + 1)
.unwrap_or(now)
.max(now);
// A relay-signed roster of a channel the relay is itself a member of (the
// relay's moderation-DM key participates in the {relay, recipient} DM used
// for moderation notices) MUST retain the relay's own `p` tag. nostr's
// default `build_with_ctx` strips any `p` tag matching the signer, which
// would drop the relay from the snapshot and fail migration 0032's roster
// fence against the canonical two-member DM. `allow_self_tagging` keeps the
// snapshot faithful to `channel_members`.
let event = EventBuilder::new(Kind::Custom(KIND_NIP29_GROUP_MEMBERS as u16), "")
.tags(tags)
.allow_self_tagging()
.custom_created_at(nostr::Timestamp::from(ts))
.sign_with_keys(&state.relay_keypair)
.map_err(|error| anyhow::anyhow!("failed to sign member snapshot: {error}"))?;
let (stored, inserted) = member_snapshot
.replace_member_event(tenant.community(), channel_id, &event)
.await?;
Ok(inserted.then_some(stored))
}
async fn dispatch_group_members_event(
tenant: &TenantContext,
state: &Arc<AppState>,
stored: Option<buzz_core::StoredEvent>,
relay_pubkey_hex: &str,
) {
if let Some(stored) = stored {
dispatch_persistent_event(
tenant,
state,
&stored,
KIND_NIP29_GROUP_MEMBERS,View on GitHub (pinned to dad5a33865)
Solutions
- Verify BUZZ_RELAY_PRIVATE_KEY is a valid 64-char hex secp256k1 private key; relay startup already validates via nostr::Keys::parse — re-run with a fresh `just bootstrap` key if unsure.
- Restart the relay so state.relay_keypair is rebuilt from configuration rather than a stale value.
- Check the wrapped {error} detail in logs for the underlying secp256k1/nostr failure and fix that root cause.
- Run `just test-unit` for the relay crate to confirm keypair/signing setup after config changes.
Example fix
// before: keypair loaded from ad-hoc string
let keys = Keys::parse(env::var("RELAY_KEY").unwrap().as_str())?;
// after: validated at startup via relay_keypair_from_config
let keys = relay_keypair_from_config(config.relay_private_key.as_deref())?; Defensive patterns
Strategy: try-catch
Validate before calling
let keys = nostr::Keys::parse(&hex_key)?;
if keys.public_key().to_bytes().len() != 32 { return Err(anyhow!("bad relay key")); } Try / catch
match store_group_members_event(...) {
Err(e) if e.to_string().contains("failed to sign member snapshot") => {
tracing::error!("relay keypair unusable: {e:#}");
// reload keypair from config and retry once
}
other => other?,
} Prevention
- Validate BUZZ_RELAY_PRIVATE_KEY with nostr::Keys::parse at startup before serving traffic.
- Never hand-roll key loading; use relay_keypair_from_config as the single source.
- Log the wrapped signing error chain ({error:#}) for root cause.
When it happens
Trigger: Calling store_group_members_event (directly or via emit_group_discovery_events / reconcile_large_channel_member_snapshots) when the relay_keypair held in state is invalid, corrupted, or fails during signing. Happens when the keypair was constructed from a malformed BUZZ_RELAY_PRIVATE_KEY or the nostr Keys object became unusable.
Common situations: Relay started with a misconfigured BUZZ_RELAY_PRIVATE_KEY (wrong length, non-hex, zero key); a relay keypair that parses but is rejected by the nostr library during secp256k1 signing; environment drift after manual edits to .env; running reconcile against a relay identity that was regenerated.
Related errors
- failed to sign moderation notice: {e}
- failed to sign system message: {e}
- build_ref_state_event: {e}
- sign roster
- an admin cannot ban or time out a community owner or fellow
AI-assisted analysis of block/buzz@dad5a33865 (2026-08-30).
Data as JSON: /api/errors/3128fe74169a5b83.
Report an issue: GitHub.