block/buzz · error

sign kind:39000: {e}

Error message

sign kind:39000: {e}

What it means

While republishing a channel's kind:39000 (NIP-29 channel metadata) snapshot, EventBuilder::sign_with_keys(&relay_keys) returned an error, which reconcile_channels wraps with this message. Signing is a pure secp256k1 operation over the assembled tags, and since the keys already passed Keys::parse, a failure here is essentially an internal/unexpected condition (secp256k1 backend error) rather than an input problem — the Tag::parse calls that build the tags fail separately with their own messages. The underlying error is appended as {e}.

Source

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

                    if !desc.is_empty() {
                        tags.push(Tag::parse(["about", desc])?);
                    }
                }
                if channel.visibility == "private" {
                    tags.push(Tag::parse(["private"])?);
                } else {
                    tags.push(Tag::parse(["public"])?);
                }
                if channel.channel_type == "dm" {
                    tags.push(Tag::parse(["hidden"])?);
                }
                tags.push(Tag::parse(["closed"])?);
                tags.push(Tag::parse(["t", &channel.channel_type])?);

                let event = EventBuilder::new(Kind::Custom(39000), "")
                    .tags(tags)
                    .sign_with_keys(&relay_keys)
                    .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}"))?;

View on GitHub (pinned to f956e6fe06)

Solutions

  1. Re-run the command once — if it succeeds, it was transient; if it persists it is deterministic and environmental.
  2. Capture the {e} suffix and check for secp256k1/nostr version skew: `cargo tree -p buzz-admin -i secp256k1` and ensure nostr and secp256k1 versions are the ones the workspace pins (run `cargo update` rollback or use Cargo.lock as committed).
  3. Re-validate the key independently (`Keys::parse` on the same value in a scratch binary or `nostr-tools key check` equivalent) to rule out a subtly corrupted value that still parses.
  4. If reproducible with a pinned lockfile, report it with the full {e} text — this path should be unreachable for a parsed key.
Defensive patterns

Strategy: validation

Validate before calling

# keys are the only realistic input factor: pre-verify before reconcile
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

match cmd.status() { Err if stderr.contains("sign kind:39000") => retry once, then capture stderr + `cargo tree -i secp256k1` for a bug report }

Prevention

When it happens

Trigger: A secp256k1 signing error surfacing from the nostr library — in practice this almost never fires: the key parsed cleanly and the event content is empty. If you see it, capture {e}; historically such errors indicate a corrupted key object or a nostr/secp256k1 version incompatibility after a dependency bump.

Common situations: After a workspace-wide `cargo update` that pulled an incompatible nostr/secp256k1 pairing; building with a patched/miscompiled crypto backend; otherwise not reproducible on re-run.

Related errors


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