block/buzz · critical · anyhow::Error
Failed to bootstrap relay owner (required when…
Error message
Failed to bootstrap relay owner (required when BUZZ_REQUIRE_RELAY_MEMBERSHIP=true): {e} What it means
Fatal startup error: db.bootstrap_owner(community, owner_pubkey) — the idempotent call guaranteeing RELAY_OWNER_PUBKEY holds the owner role in the deployment community — failed while BUZZ_REQUIRE_RELAY_MEMBERSHIP=true. A membership-enforcing relay without a bootstrapped owner cannot be administered, so the relay fails fast rather than start broken.
Solutions
- Read the {e} detail to classify connectivity vs permissions vs schema
- Verify the DB role can write the membership/role tables used by bootstrap_owner
- Restart after Postgres is stable — the call is idempotent and re-runs safely every startup
- Confirm RELAY_OWNER_PUBKEY is the intended admin key before retrying, since it will be promoted to owner
Defensive patterns
Strategy: retry
Validate before calling
# Verify the role can write membership tables before deploy:
psql "$DATABASE_URL" -c "insert into relay_members (community_id, pubkey, role) values ('00000000-0000-0000-0000-000000000000','00','member') on conflict do nothing" 2>&1 | head -1 Try / catch
// Distinguish transient (restart with backoff) from permanent (grants/schema) // by the wrapped sqlx error text before alerting.
Prevention
- bootstrap_owner runs every startup and is idempotent — restart is the fix once the DB cause is resolved
- Ensure RELAY_OWNER_PUBKEY is correct before first boot; it will be promoted to owner
When it happens
Trigger: DB failure during the owner upsert/role promotion: transient connection error, permission denied on the members/roles tables, or a schema/constraint mismatch from unapplied migrations.
Common situations: Same class as the other boot-time membership writes: Postgres not fully healthy at relay boot, least-privilege role missing rights, or a database restored without the full schema.
Related errors
- Failed to backfill pubkey_allowlist (required when…
- Failed to ensure deployment community (required when…
- Audit DB connection failed
- BUZZ_RELAY_PRIVATE_KEY is required when…
- Cannot derive a community host from BUZZ_RELAY_URL
AI-assisted analysis of block/buzz@ef2aa1ae38 (2026-08-20).
Data as JSON: /api/errors/e4100795a3bf37d8.
Report an issue: GitHub.
Appendix: source
Thrown at crates/buzz-relay/src/main.rs:420
}
}
}
}
// NIP-43: ensure the configured relay owner always holds the owner role
// within the deployment community.
if let (Some(community), Some(owner_pubkey)) =
(deployment_community, config.relay_owner_pubkey.as_ref())
{
match db.bootstrap_owner(community, owner_pubkey).await {
Ok(()) => info!(pubkey = %owner_pubkey, "Relay owner bootstrapped"),
Err(e) => {
if config.require_relay_membership {
// Membership enforcement is on — a missing owner means no one
// can administer the relay. Fail fast rather than silently start
// in a broken state.
error!("Fatal: failed to bootstrap relay owner with membership enforcement enabled: {e}");
return Err(anyhow::anyhow!(
"Failed to bootstrap relay owner (required when BUZZ_REQUIRE_RELAY_MEMBERSHIP=true): {e}"
));
} else {
error!(
"Failed to bootstrap relay owner (non-fatal, membership not required): {e}"
);
}
}
}
}
// NIP-33: backfill d_tag for any existing parameterized replaceable events
// that predate the column addition. Idempotent — no-ops when fully populated.
match db.backfill_d_tags().await {
Ok(0) => {}
Ok(n) => info!("Backfilled d_tag for {n} NIP-33 events"),
Err(e) => error!("Failed to backfill d_tags: {e}"),
}View on GitHub (pinned to ef2aa1ae38)