block/buzz · error · anyhow::Error

RELAY_URL host ' ' is not mapped to a community. buzz-admin…

Error message

RELAY_URL host '{host}' is not mapped to a community.
buzz-admin operates on the configured relay's community; ensure the relay has started and seeded its community (or set RELAY_URL to a mapped host).

What it means

Every buzz-admin operation is scoped to one community. resolve_admin_tenant derives an authority from RELAY_URL via relay_url_authority (host plus explicit non-default port, IPv6 brackets kept) and looks it up in the communities table. No row for that exact authority — which the relay seeds at startup — yields this error. Because the port matters, RELAY_URL=ws://localhost:3000 resolves 'localhost:3000', not 'localhost'.

Solutions

  1. Start the relay once against the same DATABASE_URL (just relay) so it seeds its community, then retry.
  2. Check what is seeded: SELECT id, host FROM communities; and align RELAY_URL so its authority matches a row exactly (include the port, e.g. ws://localhost:3000).
  3. Confirm DATABASE_URL for the CLI session points at the same database the relay uses.
  4. If the host is genuinely new, let the relay seed it rather than inserting a row by hand.

Example fix

# before
export RELAY_URL=ws://localhost       # authority 'localhost' != seeded 'localhost:3000'
# after
export RELAY_URL=ws://localhost:3000  # authority matches the row the relay seeded
Defensive patterns

Strategy: validation

Validate before calling

-- verify the mapping exists before running any buzz-admin command
SELECT id, host FROM communities WHERE host = 'localhost:3000'; -- = relay_url_authority(RELAY_URL)
-- no row => start the relay once, or fix RELAY_URL (host AND explicit non-default port)

Prevention

When it happens

Trigger: Running buzz-admin against a database the relay has never started on (communities table empty for that host); RELAY_URL pointing at a different relay/DB than the one seeded; omitting a non-default port so the derived authority differs from the seeded one; running against a freshly restored DB dump.

Common situations: Fresh dev environment where `just relay` was never run; staging vs prod URL confusion; RELAY_URL spelled without the port the relay actually seeded.

Related errors


AI-assisted analysis of block/buzz@ef2aa1ae38 (2026-08-20). Data as JSON: /api/errors/8a653faddcc82ffe. Report an issue: GitHub.

Appendix: source

Thrown at crates/buzz-admin/src/main.rs:612

/// `buzz-admin` runs inside the relay container (`compose exec relay
/// buzz-admin …`), so it shares the relay's `RELAY_URL` and resolves the same
/// single community against the durable `communities` host map. This is
/// deliberately NOT a default tenant: an unmapped host fails closed with an
/// error, mirroring the relay's own `bind_community` row-zero seam. The CLI is
/// single-community per invocation — there is no cross-community sweep.
async fn resolve_admin_tenant(db: &Db) -> Result<TenantContext> {
    let relay_url =
        std::env::var("RELAY_URL").unwrap_or_else(|_| "ws://localhost:3000".to_string());
    // Derive the authority the *same* way startup seeding and live request
    // resolution do (`buzz_core::tenant::relay_url_authority`): host plus an
    // explicit non-default port, IPv6 brackets preserved. A plain
    // `Url::host_str()` drops the port/brackets, so for `ws://localhost:3000`
    // the admin would look up `localhost` while startup seeded `localhost:3000`
    // — and `wss://relay.example:8443` would resolve `relay.example`. Sharing
    // the helper keeps buzz-admin byte-identical to the community startup seeds.
    let host = relay_url_authority(&relay_url);
    let record = db.lookup_community_by_host(&host).await?.ok_or_else(|| {
        anyhow::anyhow!(
            "RELAY_URL host '{host}' is not mapped to a community.\n\
             buzz-admin operates on the configured relay's community; ensure the \
             relay has started and seeded its community (or set RELAY_URL to a \
             mapped host)."
        )
    })?;
    Ok(TenantContext::resolved(record.id, record.host))
}

async fn reconcile_channels(
    channel_arg: Option<String>,
    relay_key_arg: Option<String>,
) -> Result<()> {
    use buzz_core::kind::KIND_NIP29_GROUP_ADMINS;
    use buzz_db::event::EventQuery;

    let db = connect_db().await?;

View on GitHub (pinned to ef2aa1ae38)