grpc/grpc-java · critical · IOException

Failed to bind to addresses

Error message

Failed to bind to addresses ${addresses}

What it means

NettyServer.start() binds all configured listen addresses via Netty. If the aggregate bind future is unsuccessful (e.g. the very first phase of binding fails such that no per-address future can be inspected), the server closes any channels it created and throws IOException "Failed to bind to addresses <addresses>" with the underlying bind cause attached.

Solutions

  1. Read the cause (usually java.net.BindException: Address already in use) and free the port: kill the conflicting process or change the port.
  2. Bind to 0.0.0.0 / a wildcard address or a valid interface IP.
  3. Check `lsof -i :<port>` / `netstat -tlnp` to identify the holder of the port.
  4. Use an unprivileged port or run with appropriate capabilities for privileged ports.
  5. Handle the IOException in start() callers with retry/backoff for transient port conflicts.

Example fix

// before
Server server = NettyServerBuilder.forPort(80).addService(impl).build().start(); // privileged/conflicted port
// after
Server server = NettyServerBuilder.forPort(8080).addService(impl).build();
try {
  server.start();
} catch (IOException e) {
  // pick alternate port or log bind failure (e.getCause() has BindException)
}
Defensive patterns

Strategy: try-catch

Validate before calling

int port = 50051;
try (java.net.ServerSocket probe = new java.net.ServerSocket(port)) { /* port free */ } catch (java.net.BindException e) { port = 0; }

Try / catch

try {
  server.start();
} catch (IOException e) {
  if (e.getCause() instanceof java.net.BindException) {
    // port in use: choose another port or stop the conflicting process
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling start() on a NettyServer whose bind call fails overall — most commonly a port already in use (BindException), or binding to an address/interface that does not exist or is not permitted.

Common situations: Another process (or a previous non-terminated instance) already holds the port; running without privileges on a privileged port (<1024); binding to a specific interface IP that isn't assigned; SO_REUSEADDR misconfiguration across platforms.

Related errors


AI-assisted analysis of grpc/grpc-java@64daddc1f3 (2026-09-08). Data as JSON: /api/errors/9733fa7ab0933918. Report an issue: GitHub.

Appendix: source

Thrown at netty/src/main/java/io/grpc/netty/NettyServer.java:343

            new Callable<Map<ChannelFuture, SocketAddress>>() {
          @Override
          public Map<ChannelFuture, SocketAddress> call() {
            Map<ChannelFuture, SocketAddress> bindFutures = new HashMap<>();
            for (SocketAddress address: addresses) {
                ChannelFuture future = b.bind(address);
                channelGroup.add(future.channel());
                bindFutures.put(future, address);
            }
            return bindFutures;
          }
        }
    );
    Map<ChannelFuture, SocketAddress> channelFutures =
        bindCallFuture.awaitUninterruptibly().getNow();

    if (!bindCallFuture.isSuccess()) {
      channelGroup.close().awaitUninterruptibly();
      throw new IOException(String.format("Failed to bind to addresses %s",
          addresses), bindCallFuture.cause());
    }
    final List<InternalInstrumented<SocketStats>> socketStats = new ArrayList<>();
    for (Map.Entry<ChannelFuture, SocketAddress> entry: channelFutures.entrySet()) {
      // We'd love to observe interruption, but if interrupted we will need to close the channel,
      // which itself would need an await() to guarantee the port is not used when the method
      // returns. See #6850
      final ChannelFuture future = entry.getKey();
      if (!future.awaitUninterruptibly().isSuccess()) {
        channelGroup.close().awaitUninterruptibly();
        throw new IOException(String.format("Failed to bind to address %s",
            entry.getValue()), future.cause());
      }
      final InternalInstrumented<SocketStats> listenSocketStats =
          new ListenSocket(future.channel());
      channelz.addListenSocket(listenSocketStats);
      socketStats.add(listenSocketStats);
      future.channel().closeFuture().addListener(new ChannelFutureListener() {

View on GitHub (pinned to 64daddc1f3)