{"record":{"id":"f6fba5f32b84583c","repo":"FuelLabs/fuel-core","slug":"failed-to-bind-to-address","errorCode":null,"errorMessage":"Failed to bind to address {}: {}","messagePattern":"Failed to bind to address (.+?): (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/services/block_aggregator_api/src/api/protobuf_adapter.rs","lineNumber":284,"sourceCode":"    }\n}\n\npub type APIService = ServiceRunner<UninitializedTask>;\n\npub fn incoming_and_server(\n    addr: SocketAddr,\n) -> anyhow::Result<(TcpIncoming, tonic::transport::Server)> {\n    let tcp_nodelay = true;\n    let tcp_keepalive = None;\n    let accept_http1 = false;\n\n    let tonic_server = tonic::transport::Server::default()\n        .tcp_nodelay(tcp_nodelay)\n        .tcp_keepalive(tcp_keepalive)\n        .accept_http1(accept_http1);\n\n    let incoming = TcpIncoming::bind(addr)\n        .map_err(|e| anyhow::anyhow!(\"Failed to bind to address {}: {}\", addr, e))?\n        .with_nodelay(Some(tcp_nodelay))\n        .with_keepalive(tcp_keepalive);\n\n    Ok((incoming, tonic_server))\n}\n\npub fn new_service_with_custom_incoming<B>(\n    mut tonic_server: tonic::transport::Server,\n    incoming: TcpIncoming,\n    block_aggregator: B,\n) -> anyhow::Result<APIService>\nwhere\n    B: BlocksAggregatorApi,\n{\n    let server = Server::new(block_aggregator);\n\n    let router = tonic_server.add_service(ProtoBlockAggregatorServer::new(server));\n","sourceCodeStart":266,"sourceCodeEnd":302,"githubUrl":"https://github.com/FuelLabs/fuel-core/blob/b9d4d170da3a31c9ace5f963d633b326348e0d42/crates/services/block_aggregator_api/src/api/protobuf_adapter.rs#L266-L302","documentation":"While starting the block aggregator API service, TcpIncoming::bind(addr) — the hyper/tonic listener used by the gRPC server — failed; the message includes the address and the OS error. Almost always the port is already in use, or the process lacks privileges to bind a port below 1024.","triggerScenarios":"Starting the block aggregator API with a port held by another process (second node instance, leftover process, lingering socket), binding a privileged port as non-root, or an otherwise invalid or unavailable address.","commonSituations":"Running two aggregator instances with the same config; a crashed process leaving the socket occupied; container port mappings colliding; firewall or SELinux denying the bind.","solutions":["Identify the occupant with ss -ltnp (or lsof -i :<port>) and stop or reap that process.","Change the configured bind address or port, or bind port 0 to let the OS assign a free port.","For ports below 1024, grant the capability (setcap cap_net_bind_service) or switch to a high port.","If a stale socket lingers in TIME_WAIT, wait it out or restart with address reuse enabled."],"exampleFix":"// before\nlet addr: SocketAddr = \"0.0.0.0:4280\".parse()?;\nlet (incoming, server) = new_service_and_incoming(block_aggregator, addr).await?;\n\n// after: avoid the conflict\nlet addr: SocketAddr = \"0.0.0.0:4281\".parse()?; // or pick a free port programmatically","handlingStrategy":"validation","validationCode":"use std::net::TcpListener;\n\nfn addr_bindable(addr: &std::net::SocketAddr) -> bool {\n    TcpListener::bind(addr).is_ok()\n}\n\n// before starting the block aggregator API\nif !addr_bindable(&config.addr) {\n    return Err(anyhow::anyhow!(\"address {} is not bindable (in use or privileged)\", config.addr));\n}","typeGuard":null,"tryCatchPattern":"match new_service_and_incoming(aggregator, addr).await {\n    Err(e) if e.to_string().contains(\"Failed to bind\") => {\n        // free the port (ss -ltnp | grep <port>), pick another port, or use port 0; then retry\n    }\n    rest => rest,\n}","preventionTips":["Assign one well-known port per service and document it to avoid double-starts.","Use port 0 in tests to get OS-assigned free ports.","Add a bind pre-check in orchestration scripts before launching the service.","Avoid privileged ports unless the process has cap_net_bind_service."],"tags":["grpc","network","bind","tonic","fuel-core","rust"],"backgroundTag":null,"analyzedSha":"b9d4d170da3a31c9ace5f963d633b326348e0d42","analyzedAt":"2026-08-16T08:56:42.692Z","schemaVersion":2},"datasetVersion":"2026-08-16T13:17:31.715Z"}