block/buzz · error

invalid relay key: {e}

Error message

invalid relay key: {e}

What it means

reconcile_channels() found a relay key (from --relay-key or BUZZ_RELAY_PRIVATE_KEY) but nostr's Keys::parse() rejected the value. It must decode to a valid secp256k1 secret key — 64 hex chars or bech32 nsec1… — so wrong length, stray characters, an npub (public key), or quoting artifacts make the parse fail. The parse error is appended as {e}. This is the reconcile-channels twin of the invalid BUZZ_RELAY_PRIVATE_KEY error in add-member/remove-member.

Source

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

) -> Result<()> {
    use buzz_core::kind::KIND_NIP29_GROUP_ADMINS;
    use buzz_db::event::EventQuery;

    let db = connect_db().await?;

    // Resolve relay signing key: arg > env > ephemeral. Force-republish must
    // never use an ephemeral key because it replaces an existing authoritative
    // snapshot.
    let configured_relay_key =
        relay_key_arg.or_else(|| std::env::var("BUZZ_RELAY_PRIVATE_KEY").ok());
    if channel_arg.is_some() && configured_relay_key.is_none() {
        return Err(anyhow::anyhow!(
            "--channel requires --relay-key or BUZZ_RELAY_PRIVATE_KEY"
        ));
    }
    let relay_keys = match configured_relay_key {
        Some(key_hex) => {
            Keys::parse(&key_hex).map_err(|e| anyhow::anyhow!("invalid relay key: {e}"))?
        }
        None => {
            let k = Keys::generate();
            eprintln!(
                "Warning: no relay key provided — using ephemeral key {}",
                k.public_key().to_hex()
            );
            eprintln!("Events signed with this key won't be verifiable after this run.");
            eprintln!("Pass --relay-key or set BUZZ_RELAY_PRIVATE_KEY for production use.");
            k
        }
    };

    let tenant = resolve_admin_tenant(&db).await?;
    let target_channel = channel_arg
        .as_deref()
        .map(uuid::Uuid::parse_str)
        .transpose()

View on GitHub (pinned to f956e6fe06)

Solutions

  1. Check length/charset: 64 hex chars (or full nsec1… string), no whitespace, quotes, or 0x prefix — `echo -n "$KEY" | wc -c` → 64.
  2. Make sure it is the SECRET key (hex/nsec), not the npub public key.
  3. Re-copy the exact value from the relay configuration and pass it via a shell variable to avoid quoting damage: `--relay-key "$BUZZ_RELAY_PRIVATE_KEY"`.
  4. If it still fails, print the parse suffix {e} — it names the exact malformation (bad bech32 checksum, invalid hex, wrong length).

Example fix

# before
buzz-admin reconcile-channels --relay-key 0x8a2f...   # 0x prefix rejected

# after
buzz-admin reconcile-channels --relay-key 8a2f...            # bare 64-hex secret
Defensive patterns

Strategy: validation

Validate before calling

# validate whatever key source reconcile will use
key="${RELAY_KEY_ARG:-${BUZZ_RELAY_PRIVATE_KEY:-}}"
if ! [[ "$key" =~ ^([0-9a-fA-F]{64}|nsec1[02-9ac-hj-np-z]+)$ ]]; then
  echo "relay key must be 64-hex or nsec1 bech32" >&2; exit 1
fi

Prevention

When it happens

Trigger: Passing `--relay-key npub1…` (public key), a key with a 0x prefix, a value shell-quoted with embedded quotes (`--relay-key '"abc"'`), or a truncated copy-paste; or BUZZ_RELAY_PRIVATE_KEY holding the same kinds of malformed values when --relay-key is omitted.

Common situations: Secrets copied from a password manager with whitespace/newlines; .env line wraps splitting the key; operator pastes the relay's PUBLIC key because it is the one shown in relay logs.

Related errors


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