Description
The agent's WebFlux instrumentation throws NoSuchMethodError on Spring Framework 7 (Spring Boot 4) with Netty.
PR #4397 added experimental Spring Boot 4 support for Spring MVC (servlet stack), but the WebFlux (reactive stack) instrumentation was not updated and remains incompatible with Spring Framework 7.
Environment
- Agent version: 1.55.6
- Spring Boot: 4.0.x
- Spring Framework: 7.0.2
- Spring WebFlux: 7.0.2
- Reactor Netty: 1.3.1
- Netty: 4.2.9.Final
- JDK: 21
Stack trace
[reactor-http-nio-2] ERROR co.elastic.apm.agent.bci.IndyBootstrap - Advice threw an exception, this should never happen!
java.lang.NoSuchMethodError: 'java.util.List org.springframework.http.HttpHeaders.get(java.lang.Object)'
at co.elastic.apm.agent.springwebflux.DispatcherHandlerInstrumentation$HandleAdvice.onEnter(DispatcherHandlerInstrumentation.java:64) ~[elastic-apm-agent-aefc330832b1a172028a4ec17f6d4d20-29542a5269d2cc8773f457e12848a276.jar:1.55.6]
at org.springframework.web.reactive.DispatcherHandler.handle(DispatcherHandler.java:139) ~[spring-webflux-7.0.2.jar:7.0.2]
at org.springframework.web.server.handler.DefaultWebFilterChain.lambda$filter$0(DefaultWebFilterChain.java:107) ~[spring-web-7.0.2.jar:7.0.2]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:45) ~[reactor-core-3.6.11.jar:3.6.11]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[reactor-core-3.6.11.jar:3.6.11]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.6.11.jar:3.6.11]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[reactor-core-3.6.11.jar:3.6.11]
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) ~[reactor-core-3.6.11.jar:3.6.11]
at reactor.core.publisher.Mono.subscribe(Mono.java:4576) ~[reactor-core-3.6.11.jar:3.6.11]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:265) ~[reactor-core-3.6.11.jar:3.6.11]
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[reactor-core-3.6.11.jar:3.6.11]
at reactor.core.publisher.Mono.subscribe(Mono.java:4576) ~[reactor-core-3.6.11.jar:3.6.11]
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.subscribeNext(MonoIgnoreThen.java:265) ~[reactor-core-3.6.11.jar:3.6.11]
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:51) ~[reactor-core-3.6.11.jar:3.6.11]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[reactor-core-3.6.11.jar:3.6.11]
at reactor.core.publisher.MonoDeferContextual.subscribe(MonoDeferContextual.java:55) ~[reactor-core-3.6.11.jar:3.6.11]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[reactor-core-3.6.11.jar:3.6.11]
at reactor.netty.http.server.HttpServer$HttpServerHandle.onStateChange(HttpServer.java:1344) ~[reactor-netty-http-1.3.1.jar:1.3.1]
at reactor.netty.ReactorNetty$CompositeConnectionObserver.onStateChange(ReactorNetty.java:730) ~[reactor-netty-core-1.3.1.jar:1.3.1]
at reactor.netty.transport.ServerTransport$ChildObserver.onStateChange(ServerTransport.java:489) ~[reactor-netty-core-1.3.1.jar:1.3.1]
at reactor.netty.http.server.HttpServerOperations.handleDefaultHttpRequest(HttpServerOperations.java:863) ~[reactor-netty-http-1.3.1.jar:1.3.1]
at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:789) ~[reactor-netty-http-1.3.1.jar:1.3.1]
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:115) ~[reactor-netty-core-1.3.1.jar:1.3.1]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:356) ~[netty-transport-4.2.9.Final.jar:4.2.9.Final]
at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:283) ~[reactor-netty-http-1.3.1.jar:1.3.1]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:354) ~[netty-transport-4.2.9.Final.jar:4.2.9.Final]
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:434) ~[netty-transport-4.2.9.Final.jar:4.2.9.Final]
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:361) ~[netty-codec-base-4.2.9.Final.jar:4.2.9.Final]
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:325) ~[netty-codec-base-4.2.9.Final.jar:4.2.9.Final]
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:249) ~[netty-transport-4.2.9.Final.jar:4.2.9.Final]
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:354) ~[netty-transport-4.2.9.Final.jar:4.2.9.Final]
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1429) ~[netty-transport-4.2.9.Final.jar:4.2.9.Final]
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:918) ~[netty-transport-4.2.9.Final.jar:4.2.9.Final]
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:172) ~[netty-transport-4.2.9.Final.jar:4.2.9.Final]
at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.handle(AbstractNioChannel.java:445) ~[netty-transport-4.2.9.Final.jar:4.2.9.Final]
at io.netty.channel.nio.NioIoHandler$DefaultNioRegistration.handle(NioIoHandler.java:388) ~[netty-transport-4.2.9.Final.jar:4.2.9.Final]
at io.netty.channel.nio.NioIoHandler.processSelectedKey(NioIoHandler.java:596) ~[netty-transport-4.2.9.Final.jar:4.2.9.Final]
at io.netty.channel.nio.NioIoHandler.processSelectedKeysOptimized(NioIoHandler.java:571) ~[netty-transport-4.2.9.Final.jar:4.2.9.Final]
at io.netty.channel.nio.NioIoHandler.processSelectedKeys(NioIoHandler.java:512) ~[netty-transport-4.2.9.Final.jar:4.2.9.Final]
at io.netty.channel.nio.NioIoHandler.run(NioIoHandler.java:484) ~[netty-transport-4.2.9.Final.jar:4.2.9.Final]
at io.netty.channel.SingleThreadIoEventLoop.runIo(SingleThreadIoEventLoop.java:225) ~[netty-transport-4.2.9.Final.jar:4.2.9.Final]
at io.netty.channel.SingleThreadIoEventLoop.run(SingleThreadIoEventLoop.java:196) ~[netty-transport-4.2.9.Final.jar:4.2.9.Final]
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:1195) ~[netty-common-4.2.9.Final.jar:4.2.9.Final]
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) ~[netty-common-4.2.9.Final.jar:4.2.9.Final]
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) ~[netty-common-4.2.9.Final.jar:4.2.9.Final]
at java.lang.Thread.run(Thread.java:1583) [?:?]
Expected behavior
The WebFlux instrumentation should work with Spring Framework 7 / Spring Boot 4, similar to the MVC support added in #4397.
Description
The agent's WebFlux instrumentation throws
NoSuchMethodErroron Spring Framework 7 (Spring Boot 4) with Netty.PR #4397 added experimental Spring Boot 4 support for Spring MVC (servlet stack), but the WebFlux (reactive stack) instrumentation was not updated and remains incompatible with Spring Framework 7.
Environment
Stack trace
Expected behavior
The WebFlux instrumentation should work with Spring Framework 7 / Spring Boot 4, similar to the MVC support added in #4397.