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
- 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).
- 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.
- 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.
- 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
- Source the relay's .env in every shell/script that runs buzz-admin member commands.
- Store the relay secret in your secret manager under a dedicated key so wrappers can inject it unattended.
- Remember the rule split: reconcile-channels only needs a key with --channel; add-member/remove-member always do.
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
- invalid BUZZ_RELAY_PRIVATE_KEY: {e}
- invalid relay key: {e}
- Redis pool creation failed: {e}
- --channel requires --relay-key or BUZZ_RELAY_PRIVATE_KEY
- sign kind:39000: {e}
AI-assisted analysis of block/buzz@f956e6fe06 (2026-08-16).
Data as JSON: /api/errors/41d530b34cd9be4c.
Report an issue: GitHub.