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
- Read the cause (usually java.net.BindException: Address already in use) and free the port: kill the conflicting process or change the port.
- Bind to 0.0.0.0 / a wildcard address or a valid interface IP.
- Check `lsof -i :<port>` / `netstat -tlnp` to identify the holder of the port.
- Use an unprivileged port or run with appropriate capabilities for privileged ports.
- 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
- Use port 0 (ephemeral) or check port availability before start()
- Ensure old server instances call shutdown() in tests
- Avoid privileged ports below 1024 without root
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
- Failed to bind to address
- All xds transports for authority are in backoff
- Can't set TLS settings for ALTS
- Cannot verify hostname
- ChannelLogger is not set in Builder
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)