block/buzz · critical · anyhow::Error
RELAY_OWNER_PUBKEY required when BUZZ_REQUIRE_RELAY_MEMBERSH
Error message
RELAY_OWNER_PUBKEY required when BUZZ_REQUIRE_RELAY_MEMBERSHIP=true
What it means
With BUZZ_REQUIRE_RELAY_MEMBERSHIP=true (NIP-43 enforcement) the relay requires a valid RELAY_OWNER_PUBKEY. config.rs strips invalid values with only a warning, so this fatal error fires when the variable is unset or not a valid 64-char hex pubkey — failing fast prevents starting a relay nobody can administer.
Source
Thrown at crates/buzz-relay/src/main.rs:239
Ok(false) => {}
Err(e) => {
error!(
"Replica fence disabled — floor guard verification failed: {e}. \
All cursor reads stay on the writer."
);
}
}
// NIP-43: if membership enforcement is on, a valid owner pubkey is required.
// config.rs already strips invalid values with a warning; catch the resulting
// None here so we fail fast with a clear message rather than starting a relay
// that no one can administer.
if config.require_relay_membership && config.relay_owner_pubkey.is_none() {
error!(
"BUZZ_REQUIRE_RELAY_MEMBERSHIP=true but RELAY_OWNER_PUBKEY is not set or invalid. \
Set RELAY_OWNER_PUBKEY to a valid 64-char hex pubkey."
);
return Err(anyhow::anyhow!(
"RELAY_OWNER_PUBKEY required when BUZZ_REQUIRE_RELAY_MEMBERSHIP=true"
));
}
// NIP-43: relay membership requires a stable signing key.
// Check this before any DB mutations so we fail fast — no point backfilling
// or bootstrapping if we'll reject the config anyway.
if config.require_relay_membership && config.relay_private_key.is_none() {
return Err(anyhow::anyhow!(
"BUZZ_RELAY_PRIVATE_KEY is required when BUZZ_REQUIRE_RELAY_MEMBERSHIP=true. \
NIP-43 events signed with an ephemeral key become unverifiable after restart."
));
}
// NIP-43 / multi-tenant: seed the deployment's *own* community before any
// membership backfill or owner bootstrap, so those writes are scoped to a
// real `(community_id, pubkey)` and not a global pubkey. The host is derived
// from `relay_url` with the *same* normalization request resolution usesView on GitHub (pinned to f956e6fe06)
Solutions
- Set RELAY_OWNER_PUBKEY to the raw 64-character hex x-only pubkey of the admin key
- If the value looks right, strip whitespace/quotes/0x prefix introduced by the secret store
- Or set BUZZ_REQUIRE_RELAY_MEMBERSHIP=false if enforcement was enabled by mistake
Example fix
# before BUZZ_REQUIRE_RELAY_MEMBERSHIP=true RELAY_OWNER_PUBKEY=npub1abc...xyz # invalid: bech32, not hex # after BUZZ_REQUIRE_RELAY_MEMBERSHIP=true RELAY_OWNER_PUBKEY=3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d
Defensive patterns
Strategy: validation
Validate before calling
# Assert a valid 64-char hex owner pubkey before boot when enforcement is on.
if [ "$BUZZ_REQUIRE_RELAY_MEMBERSHIP" = "true" ]; then
[[ "$RELAY_OWNER_PUBKEY" =~ ^[0-9a-fA-F]{64}$ ]] || { echo 'RELAY_OWNER_PUBKEY must be 64 hex chars'; exit 1; }
fi Type guard
fn is_valid_owner_pubkey(s: &str) -> bool {
s.len() == 64 && s.bytes().all(|b| b.is_ascii_hexdigit())
} Prevention
- Store the raw hex pubkey, never the npub form, in RELAY_OWNER_PUBKEY
- Add a secret-manager policy that trims whitespace from injected values
- Include the hex-format assertion in the deploy pipeline whenever enforcement is enabled
When it happens
Trigger: Enabling membership enforcement without setting RELAY_OWNER_PUBKEY; setting it to an npub1... bech32 string, a 0x-prefixed value, or a truncated/wrong-length key that config.rs discarded.
Common situations: Pasting an NIP-19 npub from a Nostr client instead of raw hex; secret-store truncation or added quotes/whitespace; enabling the flag in a new environment without porting the admin key.
Related errors
- BUZZ_RELAY_PRIVATE_KEY is required when BUZZ_REQUIRE_RELAY_M
- Configuration error: {e}
- Cannot derive a community host from BUZZ_RELAY_URL ({:?}); a
- Redis pool creation failed: {e}
- invalid BUZZ_RELAY_PRIVATE_KEY: {e}
AI-assisted analysis of block/buzz@f956e6fe06 (2026-08-16).
Data as JSON: /api/errors/df862e1c084b67c0.
Report an issue: GitHub.