{"record":{"id":"8a653faddcc82ffe","repo":"block/buzz","slug":"relay-url-host-host-is-not-mapped-to-a-communi","errorCode":null,"errorMessage":"RELAY_URL host '{host}' is not mapped to a community.\nbuzz-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).","messagePattern":"RELAY_URL host '(.+?)' is not mapped to a community\\.\nbuzz-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\\)\\.","errorType":"validation","errorClass":"anyhow::Error","httpStatus":null,"severity":"error","filePath":"crates/buzz-admin/src/main.rs","lineNumber":612,"sourceCode":"/// `buzz-admin` runs inside the relay container (`compose exec relay\n/// buzz-admin …`), so it shares the relay's `RELAY_URL` and resolves the same\n/// single community against the durable `communities` host map. This is\n/// deliberately NOT a default tenant: an unmapped host fails closed with an\n/// error, mirroring the relay's own `bind_community` row-zero seam. The CLI is\n/// single-community per invocation — there is no cross-community sweep.\nasync fn resolve_admin_tenant(db: &Db) -> Result<TenantContext> {\n    let relay_url =\n        std::env::var(\"RELAY_URL\").unwrap_or_else(|_| \"ws://localhost:3000\".to_string());\n    // Derive the authority the *same* way startup seeding and live request\n    // resolution do (`buzz_core::tenant::relay_url_authority`): host plus an\n    // explicit non-default port, IPv6 brackets preserved. A plain\n    // `Url::host_str()` drops the port/brackets, so for `ws://localhost:3000`\n    // the admin would look up `localhost` while startup seeded `localhost:3000`\n    // — and `wss://relay.example:8443` would resolve `relay.example`. Sharing\n    // the helper keeps buzz-admin byte-identical to the community startup seeds.\n    let host = relay_url_authority(&relay_url);\n    let record = db.lookup_community_by_host(&host).await?.ok_or_else(|| {\n        anyhow::anyhow!(\n            \"RELAY_URL host '{host}' is not mapped to a community.\\n\\\n             buzz-admin operates on the configured relay's community; ensure the \\\n             relay has started and seeded its community (or set RELAY_URL to a \\\n             mapped host).\"\n        )\n    })?;\n    Ok(TenantContext::resolved(record.id, record.host))\n}\n\nasync fn reconcile_channels(\n    channel_arg: Option<String>,\n    relay_key_arg: Option<String>,\n) -> Result<()> {\n    use buzz_core::kind::KIND_NIP29_GROUP_ADMINS;\n    use buzz_db::event::EventQuery;\n\n    let db = connect_db().await?;\n","sourceCodeStart":594,"sourceCodeEnd":630,"githubUrl":"https://github.com/block/buzz/blob/ef2aa1ae38fadcc0bc22b8bf6ed96b35933146be/crates/buzz-admin/src/main.rs#L594-L630","documentation":"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'.","triggerScenarios":"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.","commonSituations":"Fresh dev environment where `just relay` was never run; staging vs prod URL confusion; RELAY_URL spelled without the port the relay actually seeded.","solutions":["Start the relay once against the same DATABASE_URL (just relay) so it seeds its community, then retry.","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).","Confirm DATABASE_URL for the CLI session points at the same database the relay uses.","If the host is genuinely new, let the relay seed it rather than inserting a row by hand."],"exampleFix":"# before\nexport RELAY_URL=ws://localhost       # authority 'localhost' != seeded 'localhost:3000'\n# after\nexport RELAY_URL=ws://localhost:3000  # authority matches the row the relay seeded","handlingStrategy":"validation","validationCode":"-- verify the mapping exists before running any buzz-admin command\nSELECT id, host FROM communities WHERE host = 'localhost:3000'; -- = relay_url_authority(RELAY_URL)\n-- no row => start the relay once, or fix RELAY_URL (host AND explicit non-default port)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Run `just relay` (or the relay container) once against the same DATABASE_URL before any admin command.","Always set RELAY_URL with the full authority — port included — matching the relay's seeded host.","In scripts, assert the lookup first: one SQL query prevents a class of wrong-community admin operations."],"tags":["buzz-admin","community","tenant-resolution","relay-url","multi-tenant"],"backgroundTag":"unknown-community-host","analyzedSha":"ef2aa1ae38fadcc0bc22b8bf6ed96b35933146be","analyzedAt":"2026-08-20T04:38:24.874Z","contentChangedAt":"2026-08-20T04:38:24.874Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}