Skip to content

AbortedException from client logged at ERROR level with WebFlux functional endpoint #36811

@mv-shallow

Description

@mv-shallow

Version: org.springframework.boot:spring-boot-starter-webflux:3.5.8 / org.springframework:spring-web:6.2.14

I have a service that uses Reactor Netty.

When client closes connection before sending full request body there is a log with ERROR level:

2026-05-18T14:22:17.887+03:00 ERROR 9144 --- [tor-http-nio-11] o.s.w.s.adapter.HttpWebHandlerAdapter    : [e8392712-7] 500 Server Error for HTTP POST "/test"

reactor.netty.channel.AbortedException: Connection has been closed
	at reactor.netty.http.server.HttpServerOperations.onInboundClose(HttpServerOperations.java:931) ~[reactor-netty-http-1.2.12.jar:1.2.12]
	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
	*__checkpoint ? HTTP POST "/test" [ExceptionHandlingWebHandler]
Original Stack Trace:
		at reactor.netty.http.server.HttpServerOperations.onInboundClose(HttpServerOperations.java:931) ~[reactor-netty-http-1.2.12.jar:1.2.12]

Which is a bit unexpected since it's a client-side issue related to connection, so there is seemingly no need for it to be logged as ERROR by default and have any status code. (Also undesirable because in my case there are alerts configured for any logs with ERROR level)

I'd expect it to be logged at WARN/DEBUG/TRACE and this line does exactly that, but checkAndLogClientDisconnectedException isn't executed since response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR) returns true.

This looks like a bug since the code for "expected" behavior is there but is unreachable. If it's not a bug or a limitation of connectivity-related error handling, how can I safely provide my own handling for such case, via ExceptionHandler?

Below are some snippets for reproducing this issue

Main.java:

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

    @Bean
    RouterFunction<?> routerFunction() {
        return RouterFunctions
            .route()
            .POST(
                "/test",
                request -> request
                    .bodyToMono(String.class)
                    .flatMap(body -> ServerResponse.ok().build())
            ).build();
    }
}

build.gradle:

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.5.8'
    id 'io.spring.dependency-management' version '1.1.7'
}

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(21)
    }
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-webflux'
}

python script for producing aborted request:

import socket

HOST = "127.0.0.1"
PORT = 8080

request = (
    b"POST /test HTTP/1.1\r\n"
    b"Host: localhost\r\n"
    b"Content-Type: text/plain\r\n"
    b"Content-Length: 2\r\n"
    b"\r\n"
)

sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect((HOST, PORT))
sock.sendall(request)
sock.sendall(b"A")
sock.close()

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)type: enhancementA general enhancement

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions