block/buzz · error
invalid BUZZ_RELAY_PRIVATE_KEY: {e}
Error message
invalid BUZZ_RELAY_PRIVATE_KEY: {e} What it means
connect_member_services() found BUZZ_RELAY_PRIVATE_KEY but nostr's Keys::parse() rejected it. Keys::parse accepts a 64-char hex secret key or a bech32 nsec1… string; the error means the value does not decode to a valid secp256k1 secret key (wrong length, non-hex characters, 0x-prefixed hex, or a corrupted/placeholder value). The underlying parse error is appended as {e}.
Source
Thrown at crates/buzz-admin/src/main.rs:412
"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)
.await
.map_err(|e| anyhow::anyhow!("PubSub init failed: {e}"))?,
);
Ok((db, pubsub, relay_keypair))View on GitHub (pinned to f956e6fe06)
Solutions
- Verify the value is exactly 64 hex characters (or a well-formed nsec1… bech32 string) with no whitespace, quotes, or 0x prefix: `echo -n "$BUZZ_RELAY_PRIVATE_KEY" | wc -c` should print 64.
- Confirm it starts with a hex secret, not npub1… — npub is the PUBLIC key and cannot sign; the relay's own config/secret store has the matching nsec/hex secret.
- Re-copy the exact value from the relay's configuration (the same key the relay signs with), then re-run the subcommand.
- Sanity-check it parses standalone before retrying: `python3 -c "import sys; bytes.fromhex(sys.argv[1])" "$BUZZ_RELAY_PRIVATE_KEY"` (or any hex validator).
Example fix
# before: npub (public key) mistakenly used BUZZ_RELAY_PRIVATE_KEY=npub1abcdef... # after: 64-char hex secret key BUZZ_RELAY_PRIVATE_KEY=8i0j...64-hex-chars... (exact secret the relay process uses)
Defensive patterns
Strategy: validation
Validate before calling
# reject before running the CLI: must be 64 hex chars (or a valid nsec1 string)
key="${BUZZ_RELAY_PRIVATE_KEY:-}"
if ! [[ "$key" =~ ^[0-9a-fA-F]{64}$ ]]; then
echo "BUZZ_RELAY_PRIVATE_KEY must be 64 hex chars (got ${#key})" >&2
exit 1
fi Prevention
- Never store npub values in secret variables — npub is public and cannot sign.
- Validate key shape in CI for env files (length + hex charset) to catch truncation/whitespace early.
- Prefer bech32 nsec from a secret manager and let Keys::parse handle it, avoiding manual hex edits.
When it happens
Trigger: BUZZ_RELAY_PRIVATE_KEY is set to a public key (npub1…/66 hex chars) instead of the secret, has a 0x prefix, contains a trailing newline/quote from a .env copy, or is a bech32 nsec with a typo. Any add-member/remove-member invocation then fails after DB connect but before signing.
Common situations: Copy-pasting the relay's PUBLIC key into the env var; shell quoting mistakes (value captured with quotes `"abc"`); values read via `grep | cut` that include whitespace or CRLF from a Windows-edited .env; using a truncated 63-char hex key.
Related errors
- invalid relay key: {e}
- BUZZ_RELAY_PRIVATE_KEY is required for add-member/remove-mem
- sign kind:39000: {e}
- sign kind:39001: {e}
- sign kind:39002: {e}
AI-assisted analysis of block/buzz@f956e6fe06 (2026-08-16).
Data as JSON: /api/errors/18a6ef2bf2c36ea8.
Report an issue: GitHub.