block/buzz · critical · anyhow::Error

BUZZ_RELAY_PRIVATE_KEY must be set. Run `just bootstrap` for

Error message

BUZZ_RELAY_PRIVATE_KEY must be set. Run `just bootstrap` for local development or configure a stable 32-byte hex private key.

What it means

relay_keypair_from_config requires the relay's stable identity key from the BUZZ_RELAY_PRIVATE_KEY environment variable. This error is raised at relay startup when the variable is unset (None). The relay identity must be stable across restarts so events it signs (snapshots, ref states) remain attributable, so it refuses to generate an ephemeral key.

Source

Thrown at crates/buzz-relay/src/main.rs:52

        )
    })
}

async fn connect_audit_pool(config: &DbConfig) -> anyhow::Result<sqlx::PgPool> {
    let audit_config = DbConfig {
        read_database_url: None,
        max_connections: 5,
        min_connections: 1,
        ..config.clone()
    };
    Db::connect_writer_pool(&audit_config)
        .await
        .map_err(Into::into)
}

fn relay_keypair_from_config(relay_private_key: Option<&str>) -> anyhow::Result<nostr::Keys> {
    let hex = relay_private_key.ok_or_else(|| {
        anyhow::anyhow!(
            "BUZZ_RELAY_PRIVATE_KEY must be set. Run `just bootstrap` for local \
             development or configure a stable 32-byte hex private key."
        )
    })?;
    nostr::Keys::parse(hex).map_err(|e| anyhow::anyhow!("invalid BUZZ_RELAY_PRIVATE_KEY: {e}"))
}

/// Controls how many per-community gauge series the usage poller emits.
///
/// Datadog cost is proportional to the number of unique time-series.  With ~25
/// gauge label combinations per community, a relay hosting thousands of
/// communities would incur five-figure monthly costs if every community always
/// gets a full set of series.  This knob is the cost lever.
///
/// Fleet-wide totals (`buzz_total_*`) always emit regardless of mode.
///
/// Set via `BUZZ_USAGE_METRICS_PER_COMMUNITY`:
///   - `all` — emit per-community series for every community (default)

View on GitHub (pinned to dad5a33865)

Solutions

  1. Run `just bootstrap` to generate .env with a stable BUZZ_RELAY_PRIVATE_KEY for local development.
  2. Copy .env.example to .env and set BUZZ_RELAY_PRIVATE_KEY to a valid 64-char hex 32-byte key, then restart the relay.
  3. In CI/production, inject BUZZ_RELAY_PRIVATE_KEY into the environment (never commit the key).
  4. After fixing, confirm with the companion error 'invalid BUZZ_RELAY_PRIVATE_KEY' not appearing — the key must also parse.

Example fix

// before: shell without env
cargo run -p buzz-relay   // ERROR: BUZZ_RELAY_PRIVATE_KEY must be set
// after
. ./bin/activate-hermit && cp .env.example .env && just bootstrap && just relay
Defensive patterns

Strategy: validation

Validate before calling

if std::env::var("BUZZ_RELAY_PRIVATE_KEY").is_err() {
    eprintln!("BUZZ_RELAY_PRIVATE_KEY not set — run `just bootstrap`");
    std::process::exit(1);
}

Try / catch

let keys = relay_keypair_from_config(config.relay_private_key.as_deref())
    .context("relay identity missing; refusing to start with ephemeral key")?;

Prevention

When it happens

Trigger: Starting the relay without sourcing .env (skipping `. ./.env` or the just recipe), running the binary outside the dev environment, or a config loader failing to read .env; also hit directly in tests configured_relay_identity_is_preserved / missing_relay_identity_is_rejected.

Common situations: Fresh clone where .env was never copied from .env.example (`just bootstrap` skipped); CI job or systemd unit missing the env var; running `cargo run -p buzz-relay` from a shell where .env wasn't sourced.

Understand the failure class

Background: "environment variable is not set" and "Missing keys in environment" errors: what missing required env var messages mean and how to fix them — this error's family across 28 libraries.

Related errors


AI-assisted analysis of block/buzz@dad5a33865 (2026-09-05). Data as JSON: /api/errors/60bdf463dfa6c45a. Report an issue: GitHub.