block/buzz · error
--channel requires --relay-key or BUZZ_RELAY_PRIVATE_KEY
Error message
--channel requires --relay-key or BUZZ_RELAY_PRIVATE_KEY
What it means
reconcile_channels() refuses to run in --channel (single-channel force-republish) mode without a signing key. Reconciling one specific channel replaces that channel's existing authoritative kind:39000/39001/39002 snapshot events, so it must be signed by the same stable relay key as the originals — an ephemeral key would silently orphan the snapshot. The key can come from the --relay-key argument or BUZZ_RELAY_PRIVATE_KEY; if neither is present alongside --channel, this error fires. Without --channel, the command proceeds with a warning and an ephemeral key (acceptable for backfilling channels that have no events yet).
Source
Thrown at crates/buzz-admin/src/main.rs:489
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?;
// Resolve relay signing key: arg > env > ephemeral. Force-republish must
// never use an ephemeral key because it replaces an existing authoritative
// snapshot.
let configured_relay_key =
relay_key_arg.or_else(|| std::env::var("BUZZ_RELAY_PRIVATE_KEY").ok());
if channel_arg.is_some() && configured_relay_key.is_none() {
return Err(anyhow::anyhow!(
"--channel requires --relay-key or BUZZ_RELAY_PRIVATE_KEY"
));
}
let relay_keys = match configured_relay_key {
Some(key_hex) => {
Keys::parse(&key_hex).map_err(|e| anyhow::anyhow!("invalid relay key: {e}"))?
}
None => {
let k = Keys::generate();
eprintln!(
"Warning: no relay key provided — using ephemeral key {}",
k.public_key().to_hex()
);
eprintln!("Events signed with this key won't be verifiable after this run.");
eprintln!("Pass --relay-key or set BUZZ_RELAY_PRIVATE_KEY for production use.");
k
}
};View on GitHub (pinned to f956e6fe06)
Solutions
- Pass the relay's signing key explicitly: `buzz-admin reconcile-channels --channel <uuid> --relay-key <64-hex-or-nsec>` (use the SAME key the relay signs with).
- Or export BUZZ_RELAY_PRIVATE_KEY=<relay secret key> in the shell and re-run the command unchanged.
- If you only meant to backfill channels that have no events yet, drop --channel and run a full reconcile — the ephemeral-key path is allowed there (it prints a warning).
Example fix
# before buzz-admin reconcile-channels --channel 6f9c... # error: --channel requires --relay-key or BUZZ_RELAY_PRIVATE_KEY # after buzz-admin reconcile-channels --channel 6f9c... --relay-key $BUZZ_RELAY_PRIVATE_KEY
Defensive patterns
Strategy: validation
Validate before calling
# force-republish path requires a key: check flag/env pairing before invoking
if [ "$1" = "--channel" ] || [[ "$*" == *--channel* ]]; then
[ -n "${BUZZ_RELAY_PRIVATE_KEY:-}" ] || { echo 'pass --relay-key or set BUZZ_RELAY_PRIVATE_KEY' >&2; exit 1; }
fi Prevention
- Standardize on always exporting BUZZ_RELAY_PRIVATE_KEY for admin shells so --channel never trips the guard.
- Document that force-republish (single channel) requires the relay's real key — never a generated one.
When it happens
Trigger: `buzz-admin reconcile-channels --channel <uuid>` with neither --relay-key nor BUZZ_RELAY_PRIVATE_KEY in the environment. Typical when an operator escalates from a full reconcile (which tolerated the ephemeral-key warning) to a targeted re-publish of one channel without adding a key.
Common situations: Recovery playbooks that say 're-run reconcile for channel X' but were written assuming the env var was already exported; running from a clean CI shell where only DATABASE_URL/RELAY_URL are set.
Related errors
- invalid --channel UUID: {e}
- BUZZ_RELAY_PRIVATE_KEY is required for add-member/remove-mem
- invalid relay key: {e}
- channel {target} not found in community {}
- --host must not be empty
AI-assisted analysis of block/buzz@f956e6fe06 (2026-08-16).
Data as JSON: /api/errors/0e806916c837fdbe.
Report an issue: GitHub.