spring boot version: v3.4.0 netty version: 4.1.118.Final

Issue Background: Recently, I have been working on making my application cloud-native, and I deployed the service in a container. The process starts up, but Spring reports an error indicating that the port is already in use. I cannot find the target port being occupied within the container, and changing the port number still results in the same error.

Root Cause: Yes, I have already solved this problem. The problem was caused by an incorrect configuration of the target IP for Netty to bind to the port. Initially, I configured it to an external IP. After changing this configuration to the local IP, the service started listening on the port normally, and Spring no longer reported the error.

Regarding the Spring Issue: The error message from Spring Boot is misleading. The error indicating that the port is already in use led me to spend a significant amount of time investigating whether another application was actually using the port or if there were any restrictions on the port. I believe there is room for improvement in the error message, which is why I am raising this issue.

Here are some Spring boot error messages that I have seen: server.address=10.33.20.11 (an external IP) server.port=51500 error message:

:: Spring Boot ::                (v3.4.0)
ERROR org.springframework.boot.diagnostics.LoggingFailureAnalysisReporter -
***************************
APPLICATION FAILED TO START
***************************
Description: Web server failed to start. Port 51500 was already in use. 
Action: 
Identify and stop the process that's listening on port 51500 or configure this application to listen on another port.

(This is the error I initially saw, which took me a lot of time to confirm if the port was occupied. This is a bad log)

server.address=10.33.20.11 (an external IP) server.port=0 error message:

:: Spring Boot ::                (v3.4.0)

10:28:46.688 [main] ERROR org.springframework.boot.SpringApplication - Application run failed
org.springframework.context.ApplicationContextException: Failed to start bean 'webServerStartStop'
        at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:326) ~[spring-context-6.2.0.jar!/:6.2.0]
        at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:510) ~[spring-context-6.2.0.jar!/:6.2.0]
        at java.base/java.lang.Iterable.forEach(Unknown Source) ~[?:?]
        at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:295) ~[spring-context-6.2.0.jar!/:6.2.0]
        at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:240) ~[spring-context-6.2.0.jar!/:6.2.0]
        at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:1006) ~[spring-context-6.2.0.jar!/:6.2.0]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:630) ~[spring-context-6.2.0.jar!/:6.2.0]
        at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66) ~[spring-boot-3.4.0.jar!/:3.4.0]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) [spring-boot-3.4.0.jar!/:3.4.0]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) [spring-boot-3.4.0.jar!/:3.4.0]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:318) [spring-boot-3.4.0.jar!/:3.4.0]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1361) [spring-boot-3.4.0.jar!/:3.4.0]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1350) [spring-boot-3.4.0.jar!/:3.4.0]
        at com.huawei.iam.prpservice.PrpServiceApplication.main(PrpServiceApplication.java:28) [!/:.20251013153341]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:?]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:?]
        at java.base/java.lang.reflect.Method.invoke(Unknown Source) ~[?:?]
        at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:102) [prpservice-.20251013153341.jar:.20251013153341]
        at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:64) [prpservice-.20251013153341.jar:.20251013153341]
        at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:40) [prpservice-.20251013153341.jar:.20251013153341]
Caused by: org.springframework.boot.web.server.WebServerException: Unable to start Netty
        at org.springframework.boot.web.embedded.netty.NettyWebServer.start(NettyWebServer.java:123) ~[spring-boot-3.4.0.jar!/:3.4.0]
        at org.springframework.boot.web.reactive.context.WebServerManager.start(WebServerManager.java:55) ~[spring-boot-3.4.0.jar!/:3.4.0]
        at org.springframework.boot.web.reactive.context.WebServerStartStopLifecycle.start(WebServerStartStopLifecycle.java:41) ~[spring-boot-3.4.0.jar!/:3.4.0]
        at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:323) ~[spring-context-6.2.0.jar!/:6.2.0]
        ... 20 more
Caused by: reactor.netty.ChannelBindException: Failed to bind on [10.33.20.11:0]
        Suppressed: java.lang.Exception: #block terminated with an error
                at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:146) ~[reactor-core-3.7.0.jar!/:3.7.0]
                at reactor.core.publisher.Mono.block(Mono.java:1807) ~[reactor-core-3.7.0.jar!/:3.7.0]
                at reactor.netty.transport.ServerTransport.bindNow(ServerTransport.java:154) ~[reactor-netty-core-1.2.0.jar!/:1.2.0]
                at reactor.netty.transport.ServerTransport.bindNow(ServerTransport.java:139) ~[reactor-netty-core-1.2.0.jar!/:1.2.0]
                at org.springframework.boot.web.embedded.netty.NettyWebServer.startHttpServer(NettyWebServer.java:171) ~[spring-boot-3.4.0.jar!/:3.4.0]
                at org.springframework.boot.web.embedded.netty.NettyWebServer.start(NettyWebServer.java:115) ~[spring-boot-3.4.0.jar!/:3.4.0]
                at org.springframework.boot.web.reactive.context.WebServerManager.start(WebServerManager.java:55) ~[spring-boot-3.4.0.jar!/:3.4.0]
                at org.springframework.boot.web.reactive.context.WebServerStartStopLifecycle.start(WebServerStartStopLifecycle.java:41) ~[spring-boot-3.4.0.jar!/:3.4.0]
                at org.springframework.context.support.DefaultLifecycleProcessor.doStart(DefaultLifecycleProcessor.java:323) ~[spring-context-6.2.0.jar!/:6.2.0]
                at org.springframework.context.support.DefaultLifecycleProcessor$LifecycleGroup.start(DefaultLifecycleProcessor.java:510) ~[spring-context-6.2.0.jar!/:6.2.0]
                at java.base/java.lang.Iterable.forEach(Unknown Source) ~[?:?]
                at org.springframework.context.support.DefaultLifecycleProcessor.startBeans(DefaultLifecycleProcessor.java:295) ~[spring-context-6.2.0.jar!/:6.2.0]
                at org.springframework.context.support.DefaultLifecycleProcessor.onRefresh(DefaultLifecycleProcessor.java:240) ~[spring-context-6.2.0.jar!/:6.2.0]
                at org.springframework.context.support.AbstractApplicationContext.finishRefresh(AbstractApplicationContext.java:1006) ~[spring-context-6.2.0.jar!/:6.2.0]
                at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:630) ~[spring-context-6.2.0.jar!/:6.2.0]
                at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.java:66) ~[spring-boot-3.4.0.jar!/:3.4.0]
                at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752) [spring-boot-3.4.0.jar!/:3.4.0]
                at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439) [spring-boot-3.4.0.jar!/:3.4.0]
                at org.springframework.boot.SpringApplication.run(SpringApplication.java:318) [spring-boot-3.4.0.jar!/:3.4.0]
                at org.springframework.boot.SpringApplication.run(SpringApplication.java:1361) [spring-boot-3.4.0.jar!/:3.4.0]
                at org.springframework.boot.SpringApplication.run(SpringApplication.java:1350) [spring-boot-3.4.0.jar!/:3.4.0]
                at com.huawei.iam.prpservice.PrpServiceApplication.main(PrpServiceApplication.java:28) [!/:.20251013153341]
                at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]
                at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:?]
                at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:?]
                at java.base/java.lang.reflect.Method.invoke(Unknown Source) ~[?:?]
                at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:102) [prpservice-.20251013153341.jar:.20251013153341]
                at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:64) [prpservice-.20251013153341.jar:.20251013153341]
                at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:40) [prpservice-.20251013153341.jar:.20251013153341]

(When I changed the port to 0, the error started to change, and it made me realize that I had bound an incorrect IP address.)

Comment From: wilkinsona

@violetagg there doesn't seem to be a way for Boot to distinguish between a ChannelBindException that's due to an address that is already in use (a port clash) and an address that can't be assigned. The information is lost in reactor.netty.ChannelBindException.fail(SocketAddress, Throwable) where the cause is nulled out when it's a BindException. I wonder if this could be changed somehow so that the nature of the failure is conveyed to the catcher of the ChannelBindException?

Comment From: violetagg

let me check this

Comment From: violetagg

@wilkinsona If we start providing the cause, will this be helpful? One cannot rely on the message itself because it might be localised.

Comment From: wilkinsona

Yes, the cause would be helpful. Our port in use detection already suffers from problems with localisation but the cause would allow us to bring our Netty support into line with the other embedded servers. Thank you.

Comment From: violetagg

The fix will be available in Reactor Netty 1.2.12 and 1.3.0

Comment From: wilkinsona

Thanks very much, @violetagg.

Comment From: wilkinsona

The change has been reverted as, while it worked on macOS, it failed on Linux.