{"record":{"id":"bc2bee53f111cbf9","repo":"block/buzz","slug":"mesh-endpoint-bind-on-failed-e","errorCode":null,"errorMessage":"mesh endpoint bind on {} failed: {e}","messagePattern":"mesh endpoint bind on (.+?) failed: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/buzz-relay/src/mesh_boot.rs","lineNumber":426,"sourceCode":"/// sets `BUZZ_MESH=on` wants the mesh or wants to know why not; silently\n/// booting meshless would be the same class of bug as silently dropping to a\n/// default tenant.\npub async fn boot_mesh(\n    config: &Config,\n    redis_pool: deadpool_redis::Pool,\n    db: buzz_db::Db,\n    relay_keypair: &nostr::Keys,\n    shutting_down: Arc<AtomicBool>,\n) -> anyhow::Result<Option<MeshHandle>> {\n    if !config.mesh.enabled {\n        tracing::info!(\"mesh disabled (BUZZ_MESH is not 'on') — single-instance behavior\");\n        return Ok(None);\n    }\n\n    let endpoint = MeshEndpoint::bind(config.mesh.bind_addr)\n        .await\n        .map_err(|e| {\n            anyhow::anyhow!(\n                \"mesh endpoint bind on {} failed: {e}\",\n                config.mesh.bind_addr\n            )\n        })?;\n    let runtime_id = endpoint.runtime_id();\n    let addrs = advertise_addrs(&endpoint);\n    tracing::info!(\n        runtime_id = %runtime_id,\n        bind_addr = %config.mesh.bind_addr,\n        advertise_addrs = ?addrs,\n        \"mesh endpoint bound\"\n    );\n\n    let mut local_record = GossipRecord::new(runtime_id, addrs.clone(), PROTO_VERSION);\n    local_record.capabilities = capabilities();\n    // Anchor ready-record acceptance to this deployment's relay identity: all\n    // pods share the relay signing key, so a seed attested by any other key is\n    // foreign and rejected (Wren's review — possession is not authorization).","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/block/buzz/blob/f956e6fe06a76e50cbd8fba1a162482e752e7f1a/crates/buzz-relay/src/mesh_boot.rs#L408-L444","documentation":"boot_mesh (mesh_boot.rs) runs only when BUZZ_MESH is on/true/1 (strict opt-in, config.rs:605). It binds an iroh QUIC endpoint — MeshEndpoint::bind (endpoint.rs:19) builds Endpoint with the given bind_addr and RelayMode::Disabled, and both builder and bind errors collapse into MeshError::Transport(String) — on BUZZ_MESH_BIND_ADDR, default 0.0.0.0:3478 (UDP). This error wraps that failure with the address. Failure is fatal by design: an operator who asked for the mesh gets it or gets told why not.","triggerScenarios":"BUZZ_MESH=on while UDP 3478 is already taken — 3478 is the standard STUN port, so coturn/turnserver or another relay replica commonly owns it; container seccomp/firewall denying UDP socket creation; BUZZ_MESH_BIND_ADDR naming an IP that does not exist on the host.","commonSituations":"Co-locating the relay with a TURN server (both default to 3478); k8s hostNetwork pods; multiple mesh-enabled replicas on one node without distinct BUZZ_MESH_BIND_ADDR; restrictive container securityContext blocking UDP.","solutions":["Find who holds the UDP port: ss -lunp 'sport = :3478' — stop that process or move the mesh elsewhere.","Set BUZZ_MESH_BIND_ADDR to a free UDP port and open it in firewalls/security groups so peers can dial it.","If the mesh was not intended, unset BUZZ_MESH (anything other than on/true/1 keeps exact single-instance behavior).","In containers, ensure UDP is allowed by securityContext/NetworkPolicy and the bind IP exists on an interface."],"exampleFix":"# before: BUZZ_MESH=on with the default bind — coturn already owns UDP 3478\n#   Error: mesh endpoint bind on 0.0.0.0:3478 failed: ...\n\n# after\nBUZZ_MESH=on\nBUZZ_MESH_BIND_ADDR=0.0.0.0:3479","handlingStrategy":"validation","validationCode":"// Pre-flight: confirm the mesh UDP port is free before booting with BUZZ_MESH=on.\nfn udp_port_available(addr: std::net::SocketAddr) -> bool {\n    std::net::UdpSocket::bind(addr).is_ok()\n}\n\nif let Ok(mesh) = std::env::var(\"BUZZ_MESH\") {\n    if mesh.eq_ignore_ascii_case(\"on\") || mesh == \"true\" || mesh == \"1\" {\n        let bind: std::net::SocketAddr = std::env::var(\"BUZZ_MESH_BIND_ADDR\")\n            .unwrap_or_else(|_| \"0.0.0.0:3478\".into())\n            .parse()\n            .expect(\"BUZZ_MESH_BIND_ADDR must parse\");\n        assert!(udp_port_available(bind), \"mesh UDP {bind} busy — often coturn/STUN on 3478\");\n    }\n}","typeGuard":"fn is_mesh_bind_error(e: &anyhow::Error) -> bool {\n    e.to_string().starts_with(\"mesh endpoint bind\")\n}","tryCatchPattern":"let endpoint = match MeshEndpoint::bind(config.mesh.bind_addr).await {\n    Ok(ep) => ep,\n    Err(e) => {\n        tracing::error!(addr = %config.mesh.bind_addr, %e,\n            \"mesh bind failed — check `ss -lunp 'sport = :3478'` for a STUN/TURN holder\");\n        return Err(anyhow!(\"mesh endpoint bind on {} failed: {e}\", config.mesh.bind_addr));\n    }\n};","preventionTips":["Never co-locate the mesh and a TURN/STUN server on UDP 3478 — pick distinct ports in env templates","Add a UDP-port pre-flight to entrypoints when BUZZ_MESH=on","Document BUZZ_MESH_BIND_ADDR next to firewall/security-group rules so they change together"],"tags":["rust","mesh","iroh","quic","udp","port-bind","startup"],"backgroundTag":"udp-port-bind-failed","analyzedSha":"f956e6fe06a76e50cbd8fba1a162482e752e7f1a","analyzedAt":"2026-08-16T22:11:40.750Z","schemaVersion":2},"datasetVersion":"2026-08-16T23:17:17.608Z"}