{"record":{"id":"df862e1c084b67c0","repo":"block/buzz","slug":"relay-owner-pubkey-required-when-buzz-require-rela","errorCode":null,"errorMessage":"RELAY_OWNER_PUBKEY required when BUZZ_REQUIRE_RELAY_MEMBERSHIP=true","messagePattern":"RELAY_OWNER_PUBKEY required when BUZZ_REQUIRE_RELAY_MEMBERSHIP=true","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"crates/buzz-relay/src/main.rs","lineNumber":239,"sourceCode":"        Ok(false) => {}\n        Err(e) => {\n            error!(\n                \"Replica fence disabled — floor guard verification failed: {e}. \\\n                 All cursor reads stay on the writer.\"\n            );\n        }\n    }\n\n    // NIP-43: if membership enforcement is on, a valid owner pubkey is required.\n    // config.rs already strips invalid values with a warning; catch the resulting\n    // None here so we fail fast with a clear message rather than starting a relay\n    // that no one can administer.\n    if config.require_relay_membership && config.relay_owner_pubkey.is_none() {\n        error!(\n            \"BUZZ_REQUIRE_RELAY_MEMBERSHIP=true but RELAY_OWNER_PUBKEY is not set or invalid. \\\n             Set RELAY_OWNER_PUBKEY to a valid 64-char hex pubkey.\"\n        );\n        return Err(anyhow::anyhow!(\n            \"RELAY_OWNER_PUBKEY required when BUZZ_REQUIRE_RELAY_MEMBERSHIP=true\"\n        ));\n    }\n\n    // NIP-43: relay membership requires a stable signing key.\n    // Check this before any DB mutations so we fail fast — no point backfilling\n    // or bootstrapping if we'll reject the config anyway.\n    if config.require_relay_membership && config.relay_private_key.is_none() {\n        return Err(anyhow::anyhow!(\n            \"BUZZ_RELAY_PRIVATE_KEY is required when BUZZ_REQUIRE_RELAY_MEMBERSHIP=true. \\\n             NIP-43 events signed with an ephemeral key become unverifiable after restart.\"\n        ));\n    }\n\n    // NIP-43 / multi-tenant: seed the deployment's *own* community before any\n    // membership backfill or owner bootstrap, so those writes are scoped to a\n    // real `(community_id, pubkey)` and not a global pubkey. The host is derived\n    // from `relay_url` with the *same* normalization request resolution uses","sourceCodeStart":221,"sourceCodeEnd":257,"githubUrl":"https://github.com/block/buzz/blob/f956e6fe06a76e50cbd8fba1a162482e752e7f1a/crates/buzz-relay/src/main.rs#L221-L257","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"# before\nBUZZ_REQUIRE_RELAY_MEMBERSHIP=true\nRELAY_OWNER_PUBKEY=npub1abc...xyz   # invalid: bech32, not hex\n\n# after\nBUZZ_REQUIRE_RELAY_MEMBERSHIP=true\nRELAY_OWNER_PUBKEY=3bf0c63fcb93463407af97a5e5ee64fa883d107ef9e558472c4eb9aaaefa459d","handlingStrategy":"validation","validationCode":"# Assert a valid 64-char hex owner pubkey before boot when enforcement is on.\nif [ \"$BUZZ_REQUIRE_RELAY_MEMBERSHIP\" = \"true\" ]; then\n  [[ \"$RELAY_OWNER_PUBKEY\" =~ ^[0-9a-fA-F]{64}$ ]] || { echo 'RELAY_OWNER_PUBKEY must be 64 hex chars'; exit 1; }\nfi","typeGuard":"fn is_valid_owner_pubkey(s: &str) -> bool {\n    s.len() == 64 && s.bytes().all(|b| b.is_ascii_hexdigit())\n}","tryCatchPattern":null,"preventionTips":["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"],"tags":["config","nip-43","env-vars","startup","access-control"],"backgroundTag":"missing-env-var","analyzedSha":"f956e6fe06a76e50cbd8fba1a162482e752e7f1a","analyzedAt":"2026-08-16T22:11:40.750Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}