block/buzz · error

sign kind:39002: {e}

Error message

sign kind:39002: {e}

What it means

While republishing a channel's kind:39002 (NIP-29 member list) snapshot — p-tags of `[pubkey, "", role]` for every member plus the d-tag — EventBuilder::sign_with_keys(&relay_keys) failed and reconcile_channels wrapped it. Identical failure class to the 39000/39001 sign wrappers: keys were validated by Keys::parse earlier, so this indicates an unexpected crypto-layer error ({e}) rather than malformed member data.

Source

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

                    .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?;
        }

        reconciled += 1;
    }

    println!(
        "Reconciled {reconciled} channels ({skipped} already had events, {} total).",
        channels.len()
    );
    Ok(())
}

View on GitHub (pinned to f956e6fe06)

Solutions

  1. Re-run to check transience.
  2. Compare nostr/secp256k1 versions against the committed lockfile and rebuild clean: `cargo tree -i secp256k1` / `cargo build --locked`.
  3. Rule out the key by running any other signing subcommand (add-member) with the same BUZZ_RELAY_PRIVATE_KEY — if that also fails at signing, the environment/key is the common factor.
  4. Collect {e} and the nostr version for a bug report if it persists on pinned deps.
Defensive patterns

Strategy: validation

Validate before calling

# pre-verify the key once; member-tag content cannot cause this specific failure
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:39002") { retry once; persistent failure => check dependency pinning, then report with {e} and request id }

Prevention

When it happens

Trigger: reconcile-channels reaching the member-snapshot sign step and the secp256k1 backend returning an error; practically limited to dependency/toolchain anomalies (nostr/secp256k1 mismatch) since the inputs are pre-validated.

Common situations: Same as the other sign errors: version skew after dependency updates, patched crypto crates, exotic build targets. A channel with many members makes the signing payload larger but signing itself is O(1) over the serialized event, so size is not a realistic trigger.

Related errors


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