Describe the bug
When routing requests through Spring Cloud Gateway, the NettyRoutingFilter attempts to remove headers from a ReadOnlyHttpHeaders instance. This results in a java.lang.UnsupportedOperationException.
Although the response is still committed successfully (200 OK), the error is logged, which is misleading and suggests unexpected behavior in the filter chain.
Spring Boot version: 4.0.6/4.1.1
Spring Cloud Gateway: 2025.1.1/20.25.1.2
Sample
No sample application but i can try to create if need.
Logs:
2026-08-26T08:37:40.345Z TRACE 1 --- [gateway] [or-http-epoll-3] o.s.w.s.adapter.HttpWebHandlerAdapter : [37da73a0-12] HTTP GET "/AAA/BBB", headers={masked}
2026-08-26T08:37:40.421Z INFO 1 --- [gateway] [or-http-epoll-3] c.c.a.hub.gateway.config.LoggingFilter : Incoming request https://example.com/AAA/BBB is routed to id: BBB-ui, uri: http://BBB-ui:80/AAA/BBB
2026-08-26T08:37:40.445Z ERROR 1 --- [gateway] [or-http-epoll-3] c.c.a.h.g.h.TopLevelExceptionHandler : Caught exception
java.lang.UnsupportedOperationException
at org.springframework.http.ReadOnlyHttpHeaders.remove(ReadOnlyHttpHeaders.java:166) ~[spring-web-7.0.9.jar!/:7.0.9]
Suppressed: The stacktrace has been enhanced by Reactor, refer to additional information below:
Error has been observed at the following site(s):
*__checkpoint ⇢ org.springframework.cloud.gateway.filter.WeightCalculatorWebFilter@30704f85
*__checkpoint ⇢ org.springframework.security.web.server.authorization.AuthorizationWebFilter@43115b17
*__checkpoint ⇢ org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter@79976e07
*__checkpoint ⇢ org.springframework.security.web.server.authentication.logout.LogoutWebFilter@4f229e87
*__checkpoint ⇢ org.springframework.security.web.server.savedrequest.ServerRequestCacheWebFilter@2e66a2b
*__checkpoint ⇢ org.springframework.security.web.server.context.SecurityContextServerWebExchangeWebFilter@2475bbb3
*__checkpoint ⇢ org.springframework.security.web.server.authentication.AuthenticationWebFilter@12284f0d
*__checkpoint ⇢ org.springframework.security.oauth2.client.web.server.authentication.OAuth2LoginAuthenticationWebFilter@21cf894
*__checkpoint ⇢ org.springframework.security.oauth2.client.web.server.OAuth2AuthorizationRequestRedirectWebFilter@28fbda1c
*__checkpoint ⇢ org.springframework.security.web.server.context.ReactorContextWebFilter@682d6318
*__checkpoint ⇢ org.springframework.security.web.server.header.HttpHeaderWriterWebFilter@5515313b
*__checkpoint ⇢ org.springframework.security.config.web.server.ServerHttpSecurity$ServerWebExchangeReactorContextWebFilter@2c02c49e
*__checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy@32328dc4
*__checkpoint ⇢ HTTP GET "/AAA/BBB" [ExceptionHandlingWebHandler]
Original Stack Trace:
at org.springframework.http.ReadOnlyHttpHeaders.remove(ReadOnlyHttpHeaders.java:166) ~[spring-web-7.0.9.jar!/:7.0.9]
at org.springframework.cloud.gateway.filter.NettyRoutingFilter.lambda$filter$4(NettyRoutingFilter.java:182) ~[spring-cloud-gateway-server-webflux-5.0.2.jar!/:5.0.2]
at reactor.netty.http.client.HttpClientFinalizer.lambda$responseConnection$4(HttpClientFinalizer.java:102) ~[reactor-netty-http-1.3.7.jar!/:1.3.7]
at reactor.core.publisher.MonoFlatMapMany$FlatMapManyMain.onNext(MonoFlatMapMany.java:164) ~[reactor-core-3.8.7.jar!/:3.8.7]
at reactor.core.publisher.SerializedSubscriber.onNext(SerializedSubscriber.java:100) ~[reactor-core-3.8.7.jar!/:3.8.7]
at reactor.core.publisher.FluxRetryWhen$RetryWhenMainSubscriber.onNext(FluxRetryWhen.java:179) ~[reactor-core-3.8.7.jar!/:3.8.7]
at reactor.core.publisher.MonoCreate$DefaultMonoSink.success(MonoCreate.java:177) ~[reactor-core-3.8.7.jar!/:3.8.7]
at reactor.netty.http.client.HttpClientConnect$HttpIOHandlerObserver.onStateChange(HttpClientConnect.java:460) ~[reactor-netty-http-1.3.7.jar!/:1.3.7]
at reactor.netty.ReactorNetty$CompositeConnectionObserver.onStateChange(ReactorNetty.java:736) ~[reactor-netty-core-1.3.7.jar!/:1.3.7]
at reactor.netty.resources.DefaultPooledConnectionProvider$DisposableAcquire.onStateChange(DefaultPooledConnectionProvider.java:229) ~[reactor-netty-core-1.3.7.jar!/:1.3.7]
at reactor.netty.resources.DefaultPooledConnectionProvider$PooledConnection.onStateChange(DefaultPooledConnectionProvider.java:491) ~[reactor-netty-core-1.3.7.jar!/:1.3.7]
at reactor.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:858) ~[reactor-netty-http-1.3.7.jar!/:1.3.7]
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:115) ~[reactor-netty-core-1.3.7.jar!/:1.3.7]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357) ~[netty-transport-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:434) ~[netty-transport-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:361) ~[netty-codec-base-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:348) ~[netty-codec-base-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:470) ~[netty-codec-base-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296) ~[netty-codec-base-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:249) ~[netty-transport-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:355) ~[netty-transport-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1429) ~[netty-transport-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:918) ~[netty-transport-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:804) ~[netty-transport-classes-epoll-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.channel.epoll.AbstractEpollChannel$AbstractEpollUnsafe.handle(AbstractEpollChannel.java:487) ~[netty-transport-classes-epoll-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.channel.epoll.EpollIoHandler$DefaultEpollIoRegistration.handle(EpollIoHandler.java:349) ~[netty-transport-classes-epoll-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.channel.epoll.EpollIoHandler.processReady(EpollIoHandler.java:548) ~[netty-transport-classes-epoll-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.channel.epoll.EpollIoHandler.run(EpollIoHandler.java:491) ~[netty-transport-classes-epoll-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.channel.SingleThreadIoEventLoop.runIo(SingleThreadIoEventLoop.java:225) ~[netty-transport-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.channel.SingleThreadIoEventLoop.run(SingleThreadIoEventLoop.java:196) ~[netty-transport-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:1204) ~[netty-common-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.2.17.Final.jar!/:4.2.17.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.2.17.Final.jar!/:4.2.17.Final]
at java.base/java.lang.Thread.run(Unknown Source) ~[na:na]
2026-08-26T08:37:40.466Z ERROR 1 --- [gateway] [or-http-epoll-3] o.s.w.s.adapter.HttpWebHandlerAdapter : [37da73a0-12] Error [java.lang.UnsupportedOperationException] for HTTP GET "/AAA/BBB", but ServerHttpResponse already committed (200 OK)
Describe the bug
When routing requests through Spring Cloud Gateway, the NettyRoutingFilter attempts to remove headers from a ReadOnlyHttpHeaders instance. This results in a java.lang.UnsupportedOperationException.
Although the response is still committed successfully (200 OK), the error is logged, which is misleading and suggests unexpected behavior in the filter chain.
Spring Boot version: 4.0.6/4.1.1
Spring Cloud Gateway: 2025.1.1/20.25.1.2
Sample
No sample application but i can try to create if need.
Logs: