block/buzz · critical · anyhow::Error

mesh endpoint bind on

Error message

mesh endpoint bind on {} failed: {e}

What it means

When BUZZ_MESH=on, mesh_boot binds an iroh QUIC/UDP endpoint (MeshEndpoint::bind → iroh Endpoint::builder().bind_addr(addr).bind()) on config.mesh.bind_addr (BUZZ_MESH_BIND_ADDR, see config.rs:608). A bind failure is wrapped with the address and mesh boot aborts, which fails relay startup — the relay refuses to run a half-meshed instance.

Solutions

  1. Check the UDP listener: `ss -lunp 'sport = :<port>'` and stop the duplicate process/pod.
  2. Set BUZZ_MESH_BIND_ADDR to 0.0.0.0:<port> (or a free port) and restart.
  3. Verify the IP in BUZZ_MESH_BIND_ADDR exists on the host (`ip addr`).
  4. If mesh is not needed for this deployment, set BUZZ_MESH to something other than 'on' — mesh_boot then logs 'mesh disabled' and returns Ok(None).

Example fix

# before
BUZZ_MESH=on
BUZZ_MESH_BIND_ADDR=10.2.3.4:7777  # IP absent on this node

# after
BUZZ_MESH=on
BUZZ_MESH_BIND_ADDR=0.0.0.0:7777
Defensive patterns

Strategy: validation

Validate before calling

# UDP ports need -u; verify mesh bind is free before enabling mesh
if ss -lunH "sport = :${BUZZ_MESH_BIND_ADDR##*:}" | grep -q .; then
  echo "mesh UDP port busy" >&2; exit 1
fi
[ "${BUZZ_MESH:-off}" = "on" ] || echo "mesh off — bind not required"

Prevention

When it happens

Trigger: The iroh endpoint bind at crates/buzz-relay/src/mesh_boot.rs:423 fails when: (1) the UDP port in BUZZ_MESH_BIND_ADDR is already bound by another relay/mesh instance (AddrInUse — note UDP, so `ss -ltn` will not show it); (2) the address family/IP does not exist on the host (EADDRNOTAVAIL); (3) privileged UDP port without CAP_NET_BIND_SERVICE; (4) firewall/SELinux denying UDP bind.

Common situations: Two relay replicas configured with the same BUZZ_MESH_BIND_ADDR on one host (staging ArgoCD rollout where old pod overlaps with new); BUZZ_MESH_BIND_ADDR copied from the Terraform stack with a VPC IP that does not exist on the node; local dev with a leftover relay process still holding the UDP socket.

Related errors


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

Appendix: source

Thrown at crates/buzz-relay/src/mesh_boot.rs:426

/// sets `BUZZ_MESH=on` wants the mesh or wants to know why not; silently
/// booting meshless would be the same class of bug as silently dropping to a
/// default tenant.
pub async fn boot_mesh(
    config: &Config,
    redis_pool: deadpool_redis::Pool,
    db: buzz_db::Db,
    relay_keypair: &nostr::Keys,
    shutting_down: Arc<AtomicBool>,
) -> anyhow::Result<Option<MeshHandle>> {
    if !config.mesh.enabled {
        tracing::info!("mesh disabled (BUZZ_MESH is not 'on') — single-instance behavior");
        return Ok(None);
    }

    let endpoint = MeshEndpoint::bind(config.mesh.bind_addr)
        .await
        .map_err(|e| {
            anyhow::anyhow!(
                "mesh endpoint bind on {} failed: {e}",
                config.mesh.bind_addr
            )
        })?;
    let runtime_id = endpoint.runtime_id();
    let addrs = advertise_addrs(&endpoint);
    tracing::info!(
        runtime_id = %runtime_id,
        bind_addr = %config.mesh.bind_addr,
        advertise_addrs = ?addrs,
        "mesh endpoint bound"
    );

    let mut local_record = GossipRecord::new(runtime_id, addrs.clone(), PROTO_VERSION);
    local_record.capabilities = capabilities();
    // Anchor ready-record acceptance to this deployment's relay identity: all
    // pods share the relay signing key, so a seed attested by any other key is
    // foreign and rejected (Wren's review — possession is not authorization).

View on GitHub (pinned to 934f3325c3)