block/buzz · error

BUZZ_RELAY_PRIVATE_KEY is required for add-member/remove-mem

Error message

BUZZ_RELAY_PRIVATE_KEY is required for add-member/remove-member.
The relay must have a stable signing key to publish kind:13534 events.

What it means

Thrown by buzz-admin's connect_member_services() when the add-member/remove-member subcommands run without BUZZ_RELAY_PRIVATE_KEY set in the environment. These commands publish a signed NIP-43 kind:13534 membership list on behalf of the relay, which requires the relay's stable Nostr signing keypair; there is deliberately no ephemeral fallback because clients verify the roster against the relay's known pubkey. The error fires before any DB or Redis work beyond connect_db().

Source

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

    }

    tracing::info!(
        member_count = members.len(),
        ts,
        "NIP-43 membership list published by buzz-admin"
    );
    Ok(())
}

/// Connect to DB, Redis pub/sub, and load the relay keypair.
///
/// `BUZZ_RELAY_PRIVATE_KEY` is required — the CLI signs kind:13534 events.
async fn connect_member_services() -> Result<(Db, Arc<PubSubManager>, Keys)> {
    let db = connect_db().await?;

    let relay_keypair = {
        let hex = std::env::var("BUZZ_RELAY_PRIVATE_KEY").map_err(|_| {
            anyhow::anyhow!(
                "BUZZ_RELAY_PRIVATE_KEY is required for add-member/remove-member.\n\
                 The relay must have a stable signing key to publish kind:13534 events."
            )
        })?;
        Keys::parse(&hex).map_err(|e| anyhow::anyhow!("invalid BUZZ_RELAY_PRIVATE_KEY: {e}"))?
    };

    let redis_url =
        std::env::var("REDIS_URL").unwrap_or_else(|_| "redis://localhost:6379".to_string());

    let redis_pool = {
        let cfg = deadpool_redis::Config::from_url(&redis_url);
        cfg.create_pool(Some(deadpool_redis::Runtime::Tokio1))
            .map_err(|e| anyhow::anyhow!("Redis pool creation failed: {e}"))?
    };

    let pubsub = Arc::new(
        PubSubManager::new(&redis_url, redis_pool)

View on GitHub (pinned to f956e6fe06)

Solutions

  1. Export the relay's signing key in the shell before running: BUZZ_RELAY_PRIVATE_KEY=<64-char hex> (copy the same value the relay process uses, so the published kind:13534 events are verifiable by clients).
  2. Put it in the environment file your workflow sources (e.g. .env next to the relay config) and re-run the command from that shell.
  3. If running under systemd/cron/docker, add BUZZ_RELAY_PRIVATE_KEY to that environment (Environment=, crontab env line, or compose env_file) — a login shell export is invisible to those contexts.
  4. Never generate a fresh key for this command: events signed by any key other than the relay's own key will be rejected/ignored by clients as untrusted.

Example fix

# before
buzz-admin add-member --pubkey <hex> --role member
# error: BUZZ_RELAY_PRIVATE_KEY is required for add-member/remove-member.

# after
export BUZZ_RELAY_PRIVATE_KEY=$(grep '^BUZZ_RELAY_PRIVATE_KEY=' /path/to/relay/.env | cut -d= -f2)
buzz-admin add-member --pubkey <hex> --role member
Defensive patterns

Strategy: validation

Validate before calling

#!/usr/bin/env bash
# preflight before buzz-admin add-member/remove-member
if [ -z "${BUZZ_RELAY_PRIVATE_KEY:-}" ]; then
  echo "BUZZ_RELAY_PRIVATE_KEY is not set — export the relay's secret key" >&2
  exit 1
fi

Prevention

When it happens

Trigger: Running `buzz-admin add-member ...` or `buzz-admin remove-member ...` in a shell/process where BUZZ_RELAY_PRIVATE_KEY is unset (e.g. only RELAY_URL and DATABASE_URL exported), or running the CLI from a service unit or cron that does not source the relay's .env file.

Common situations: Operator copies the relay's .env.example but only fills in database/relay URLs; running buzz-admin on a different host than the relay without copying the key; CI scripts that intentionally omit secrets. Note the env-deletion subcommands (buzz-deletion) and reconcile-channels have different key rules, so a setup that works for those fails here.

Related errors


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