block/buzz · error
sign kind:39001: {e}
Error message
sign kind:39001: {e} What it means
While republishing a channel's kind:39001 (NIP-29 group admins, KIND_NIP29_GROUP_ADMINS) snapshot — the d-tagged addressable event listing owner/admin pubkeys as p-tags with their roles — EventBuilder::sign_with_keys(&relay_keys) failed and reconcile_channels wrapped it. Same class as the kind:39000/39002 sign errors: the key already parsed, so a failure is an unexpected secp256k1/nostr-internal condition, not bad channel data (tag construction errors are reported separately).
Source
Thrown at crates/buzz-admin/src/main.rs:601
.map_err(|e| anyhow::anyhow!("sign kind:39000: {e}"))?;
db.replace_addressable_event(tenant.community(), &event, Some(channel.id))
.await?;
}
// kind:39001 — admins
{
let mut tags: Vec<Tag> = vec![Tag::parse(["d", &channel_id_str])?];
for m in members
.iter()
.filter(|m| m.role == "owner" || m.role == "admin")
{
let pk = hex::encode(&m.pubkey);
tags.push(Tag::parse(["p", &pk, &m.role])?);
}
let event = EventBuilder::new(Kind::Custom(KIND_NIP29_GROUP_ADMINS as u16), "")
.tags(tags)
.sign_with_keys(&relay_keys)
.map_err(|e| anyhow::anyhow!("sign kind:39001: {e}"))?;
db.replace_addressable_event(tenant.community(), &event, Some(channel.id))
.await?;
}
}
// kind:39002 — members
{
let mut tags: Vec<Tag> = vec![Tag::parse(["d", &channel_id_str])?];
for m in &members {
let pk = hex::encode(&m.pubkey);
tags.push(Tag::parse(["p", &pk, "", &m.role])?);
}
let event = EventBuilder::new(Kind::Custom(39002), "")
.tags(tags)
.sign_with_keys(&relay_keys)
.map_err(|e| anyhow::anyhow!("sign kind:39002: {e}"))?;
db.replace_addressable_event(tenant.community(), &event, Some(channel.id))
.await?;View on GitHub (pinned to f956e6fe06)
Solutions
- Retry once to distinguish transient vs deterministic.
- Inspect the {e} text, then verify dependency coherence: `cargo tree -p buzz-admin -i secp256k1` and rebuild from the committed Cargo.lock (`git checkout Cargo.lock && cargo build`).
- If a custom/patched nostr crate is in use, revert to the workspace-pinned version and retest.
- Persisting failure with pinned deps: preserve the exact command, key fingerprint, and {e} for a bug report — this code path assumes signing cannot fail for parsed keys.
Defensive patterns
Strategy: validation
Validate before calling
# same pre-verify: signing can only fail on key/dependency anomalies
python3 -c "import sys; bytes.fromhex(sys.argv[1])" "$BUZZ_RELAY_PRIVATE_KEY" \
|| { echo 'relay key is not valid hex' >&2; exit 1; } Try / catch
if stderr.contains("sign kind:39001") { rerun once; if persistent, verify `cargo tree -i secp256k1` matches lockfile and report with full {e} } Prevention
- Pin crypto deps via Cargo.lock in CI builds for any binary that signs Nostr events.
- Keep a scratch command that signs any event with the same key to bisect key vs environment.
When it happens
Trigger: Deterministic or transient secp256k1 signing failures from the nostr crate during reconcile-channels with a valid relay key; realistically only seen with dependency version skew (nostr vs secp256k1) or a miscompiled crypto backend after toolchain changes.
Common situations: Post `cargo update` builds; locally patched nostr versions; cross-compiled binaries with a broken secp256k1 backend. Channel/admin data itself cannot trigger this specific message.
Related errors
- sign kind:39000: {e}
- sign kind:39002: {e}
- invalid BUZZ_RELAY_PRIVATE_KEY: {e}
- BUZZ_RELAY_PRIVATE_KEY is required for add-member/remove-mem
- invalid relay key: {e}
AI-assisted analysis of block/buzz@f956e6fe06 (2026-08-16).
Data as JSON: /api/errors/ffadcc64d869798b.
Report an issue: GitHub.