{"record":{"id":"2e3633783dc422ce","repo":"block/buzz","slug":"failed-to-bind-e","errorCode":null,"errorMessage":"Failed to bind {}: {e}","messagePattern":"Failed to bind (.+?): (.+?)","errorType":"exception","errorClass":"anyhow::Error","httpStatus":null,"severity":"critical","filePath":"crates/buzz-relay/src/main.rs","lineNumber":1448,"sourceCode":"        // retains ownership of every delayed close until its 1012 frame has\n        // been flushed and acknowledged (or its send loop cancelled).\n        let closed = if drain_jitter_ms == 0 {\n            drain_conn_manager.drain_all()\n        } else {\n            drain_conn_manager.drain_all_jittered(drain_jitter_ms).await\n        };\n        info!(\n            connections = closed,\n            jitter_ms = drain_jitter_ms,\n            max_jitter_ms = MAX_DRAIN_JITTER_MS,\n            \"Signalled restart close to all live WebSocket connections\"\n        );\n        hard_shutdown_abort\n    });\n\n    let tcp_listener = tokio::net::TcpListener::bind(&config.bind_addr)\n        .await\n        .map_err(|e| anyhow::anyhow!(\"Failed to bind {}: {e}\", config.bind_addr))?;\n    info!(addr = %config.bind_addr, \"buzz-relay TCP listening\");\n\n    #[cfg(unix)]\n    if let Some(ref uds_path) = config.uds_path {\n        use std::os::unix::fs::FileTypeExt as _;\n        match std::fs::symlink_metadata(uds_path) {\n            Ok(meta) if meta.file_type().is_socket() => {\n                let _ = std::fs::remove_file(uds_path);\n            }\n            Ok(_) => {\n                return Err(anyhow::anyhow!(\n                    \"BUZZ_UDS_PATH {uds_path} exists but is not a socket\"\n                ));\n            }\n            Err(_) => {}\n        }\n        let uds_listener = tokio::net::UnixListener::bind(uds_path)\n            .map_err(|e| anyhow::anyhow!(\"Failed to bind UDS {uds_path}: {e}\"))?;","sourceCodeStart":1430,"sourceCodeEnd":1466,"githubUrl":"https://github.com/block/buzz/blob/ef2aa1ae38fadcc0bc22b8bf6ed96b35933146be/crates/buzz-relay/src/main.rs#L1430-L1466","documentation":"This is the bind of buzz-relay's main WebSocket listener: TcpListener::bind(&config.bind_addr) in serve() (crates/buzz-relay/src/main.rs:1330). bind_addr comes from the relay config (BUZZ_BIND_ADDR, parsed by parse_bind_addr in config.rs). Any kernel bind failure is wrapped in anyhow with the full address and aborts startup.","triggerScenarios":"Binding the main relay socket fails when: (1) AddrInUse — another relay or any process already listens on that ip:port; (2) PermissionDenied — port < 1024 without privileges; (3) EADDRNOTAVAIL — BUZZ_BIND_ADDR names an IP that does not exist on this host (typical when copying a config from another machine or binding a docker-internal IP directly on the host); (4) EACCES on the port due to local firewall reserved-port ranges (ip_local_reserved_ports / SELinux).","commonSituations":"Two `just relay` sessions on one dev box; a previous relay still running inside Docker while you start one on the host; BUZZ_BIND_ADDR set to 10.x cluster IP on a laptop; switching a deployment from port 3000 to 443 without granting the capability.","solutions":["Check who holds the address: `ss -ltnp 'sport = :<port>'` and stop the duplicate listener.","Change BUZZ_BIND_ADDR to a free port/IP (e.g. 127.0.0.1:3000 for local dev) in .env.","Verify the IP in BUZZ_BIND_ADDR exists: `ip addr` — if not, bind 0.0.0.0:<port> or fix the interface address.","For privileged ports, grant CAP_NET_BIND_SERVICE or front the relay with a proxy that binds 443 for it.","In docker-compose/K8s, make sure only one replica binds a host port when using host networking."],"exampleFix":"# before\nBUZZ_BIND_ADDR=10.0.1.5:3000   # IP not present on this host\n# error: Failed to bind 10.0.1.5:3000: Cannot assign requested address\n\n# after\nBUZZ_BIND_ADDR=0.0.0.0:3000","handlingStrategy":"validation","validationCode":"# verify address exists on this host and port is free before launch\nip -4 addr | grep -F \"$BIND_IP\" || { echo \"BUZZ_BIND_ADDR IP not present\" >&2; exit 1; }\nss -ltnH \"sport = :$BIND_PORT\" | grep -q . && { echo \"port busy\" >&2; exit 1; } || true","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Bind 0.0.0.0:<port> unless a specific interface is required; it removes EADDRNOTAVAIL class failures.","Keep one relay per host/port; use container networking instead of host networking for parallel instances.","Include the bind address in health/log output (relay logs 'buzz-relay TCP listening') and check it on boot.","Automate port allocation in dev (e.g. per-worktree ports) so two worktrees never collide."],"tags":["rust","network","port-bind","startup","websocket"],"backgroundTag":"address-in-use","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"}