block/buzz · critical · anyhow::Error
mesh ready-registry publish failed
Error message
mesh ready-registry publish failed: {e} What it means
mesh_boot publishes the relay's attested ready-record to the Redis ready-registry as part of boot; the source comment is explicit — if Redis cannot take the record, peers can never discover this instance, so boot fails loudly instead of running undiscoverable. Any error from registry.publish_ready (Redis connection, TLS, auth, serialization of the attested record) is wrapped as 'mesh ready-registry publish failed' and aborts relay startup when mesh is enabled.
Solutions
- Verify Redis reachability from the relay host: `redis-cli -u <url> PING` (use rediss:// and --tls for TLS endpoints).
- Fix the URL scheme: rediss:// for TLS-encrypted Redis (ElastiCache), redis:// only for plaintext.
- Check credentials/ACLs: the relay's Redis user needs SET/PUBLISH on the ready-registry keys.
- Open network egress (security groups / NetworkPolicies) to the Redis port.
- If you only want single-instance behavior, set BUZZ_MESH to a value other than 'on' — mesh_boot then skips registry publish entirely.
Example fix
# before BUZZ_MESH=on BUZZ_REDIS_URL=redis://mesh-redis.internal:6379 # against TLS-enabled ElastiCache # after BUZZ_MESH=on BUZZ_REDIS_URL=rediss://mesh-redis.internal:6379
Defensive patterns
Strategy: retry
Validate before calling
# preflight from the relay host before enabling mesh redis-cli --tls -u "$BUZZ_REDIS_URL" PING # expect PONG
Try / catch
// at boot: retry the publish briefly before failing fast, so a restarting Redis
// does not take the relay down
let mut attempt = 0;
loop {
match registry.publish_ready(&ready_record).await {
Ok(()) => break,
Err(e) if attempt < 5 => { attempt += 1; tokio::time::sleep(Duration::from_secs(2)).await; }
Err(e) => return Err(anyhow::anyhow!("mesh ready-registry publish failed: {e}")),
}
} Prevention
- Start/verify Redis before relays in compose/ArgoCD ordering (init containers or readiness gates).
- Standardize rediss:// + TLS for ElastiCache in all environments to avoid scheme drift.
- Keep mesh registry credentials in the same secret rotation flow as the main cache to avoid partial rotations.
- Remember the fail-fast is intentional — do not silence it; fix reachability instead.
When it happens
Trigger: registry.publish_ready(&ready_record) at crates/buzz-relay/src/mesh_boot.rs:458-462 fails when: Redis is unreachable (wrong host/port in the mesh registry config), rediss:// TLS cert validation fails (ElastiCache), auth credentials are wrong (NOAUTH/WRONGPASS), the key is under a write-protected policy, or the record exceeds Redis protocol limits.
Common situations: Enabling BUZZ_MESH=on locally without the staging Redis running or reachable; ElastiCache in-transit encryption enabled but the relay's Redis URL uses redis:// instead of rediss://; rotated Redis credentials not deployed to the K8s secret; security-group rules blocking the node's egress to Redis port 6379.
Related errors
- failed to install rustls crypto provider
- failed to install rustls crypto provider
- mesh endpoint bind on
- push HTTP client
- BUZZ_UDS_PATH exists but is not a socket
AI-assisted analysis of block/buzz@934f3325c3 (2026-08-20).
Data as JSON: /api/errors/86349a1b6a92db26.
Report an issue: GitHub.
Appendix: source
Thrown at crates/buzz-relay/src/mesh_boot.rs:462
// foreign and rejected (Wren's review — possession is not authorization).
let membership = MeshMembership::new(local_record)
.with_expected_relay_pubkey(relay_keypair.public_key().to_hex());
let registry = ReadyRegistry::new(redis_pool.clone(), config.mesh.registry_refresh);
let ready_record = ReadyRecord::new(
runtime_id,
relay_keypair,
addrs,
PROTO_VERSION,
capabilities(),
);
// First publish is part of boot: if Redis can't take the attested record,
// peers can never find us — fail loudly now, not quietly forever.
registry
.publish_ready(&ready_record)
.await
.map_err(|e| anyhow::anyhow!("mesh ready-registry publish failed: {e}"))?;
tracing::info!(runtime_id = %runtime_id, "mesh ready record published");
// Readiness-gated heartbeat: publishes while the relay would pass
// readiness, clears the record on ready→not-ready and on shutdown.
let hb_flag = Arc::clone(&shutting_down);
buzz_relay_mesh::runtime::spawn_registry_heartbeat(
registry.clone(),
ready_record,
Arc::new(move || !hb_flag.load(Ordering::Relaxed)),
);
let runtime = MeshRuntime::start(endpoint, membership, Some(registry));
let owners = Arc::new(crate::audio::join::HuddleOwnerRegistry::new());
// Dial seed peers now rather than waiting for the first reconcile tick.
runtime.reconcile_now().await;
// Drain watcher: SIGTERM flips `shutting_down`; gossip `draining=true` so
// peers stop routing new sessions here, then actively drain locally-ownedView on GitHub (pinned to 934f3325c3)