spring-cloud-gateway icon indicating copy to clipboard operation
spring-cloud-gateway copied to clipboard

Error when using ModifyRequestBody and Retry filters

Open maxwo opened this issue 9 months ago • 3 comments

Describe the bug

Using the ModifyRequestBody and Retry filters causes an IllegalReferenceCountException on technical error of the target (e.g. premature closed error):

io.netty.util.IllegalReferenceCountException: refCnt: 0, decrement: 1

I witnessed this on 2.7 & 3.4 versions.

Sample

Using this code, creating a route that uses the ModifyRequestBody and Retry filters, it will trigger the exception:

@SpringBootApplication
public class DemoApplication {

    public static void main(String[] args) {
       SpringApplication.run(DemoApplication.class, args);
    }

    @Bean
    public RouteLocator rewrittenAndRetriedRoute(RouteLocatorBuilder builder) {
        return builder.routes()
            .route(p -> p
                .path("/route/*")
                .filters(f -> f
                    .modifyRequestBody(config -> {
                        config.setInClass(String.class);
                        config.setOutClass(String.class);
                        config.setRewriteFunction((exchange, body) -> Mono.just("{}"));
                    })
                    .retry(config -> {
                        config.setRetries(5);
                        config.setSeries();
                        config.setStatuses(HttpStatus.BAD_GATEWAY, HttpStatus.GATEWAY_TIMEOUT);
                        config.setExceptions(IOException.class);
                        config.setMethods(HttpMethod.GET, HttpMethod.POST, HttpMethod.PUT, HttpMethod.DELETE, HttpMethod.PATCH);
                        config.setBackoff(new RetryGatewayFilterFactory.BackoffConfig(Duration.ofMillis(5), Duration.ofMillis(10), 2, false));
                    })
                )
                .uri("http://localhost:9880/"))
            .build();
    }
}

I am using this simple NodeJS server to reproduce a technical error:

const net = require("net");
const server = net.createServer(function(socket) {
    console.log('opening connection');
    setTimeout(function() { socket.destroy(); }, 20);
});
server.listen(9880);

And curl:

$ curl localhost:8080/route/fail -XPOST -H 'Content-Type: application/json' -d '{"Hello": "World"}'

maxwo avatar Apr 18 '25 13:04 maxwo

2.7 and 3.4 must be versions of spring boot. What versions of gateway?

spencergibb avatar Apr 18 '25 13:04 spencergibb

I used the Spring Boot initializer for 3.4.4, and it seems to be using the 4.2.1 version for the gateway.

On our project, we are using 3.1.3 version of the gateway with a 2.6 Spring Boot version (I managed to reproduce the same way with 2.6, 2.7 and 3.4 though)

maxwo avatar Apr 18 '25 13:04 maxwo

I also tried using something else than a String for the modified request body, using a buffer thanks to DefaultDataBufferFactory for instance, with the same error.

maxwo avatar Apr 18 '25 13:04 maxwo