Occasionally I'm getting NPEs wehn using RestTemplate.postForObject(). I could not manually reproduce the issues, as I don't know the case when the headers "seem" to be null.

All I know is that the ClientHttpResponse is not null in those cases and correctly filled with header+body data. The next request with the exact same parameters then works again.

Maybe this has to do with https://github.com/spring-projects/spring-framework/issues/22821, because new HttpHeaders() is initialized with LinkedCaseInsensitiveMap?

Anyways I think adding (or getting) the HttpHeaders should never result in an NPE, this should be caught somewhere down the stack.

java.util.concurrent.CompletionException: java.lang.NullPointerException
    at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:314) ~[?:?]
    at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:319) ~[?:?]
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1702) ~[?:?]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
    at java.lang.Thread.run(Thread.java:834) [?:?]
Caused by: java.lang.NullPointerException
    at org.springframework.util.CollectionUtils$MultiValueMapAdapter.add(CollectionUtils.java:460) ~[spring-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.http.HttpHeaders.add(HttpHeaders.java:1565) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.http.client.HttpComponentsClientHttpResponse.getHeaders(HttpComponentsClientHttpResponse.java:71) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.http.client.BufferingClientHttpResponseWrapper.getHeaders(BufferingClientHttpResponseWrapper.java:65) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.web.client.MessageBodyClientHttpResponseWrapper.getHeaders(MessageBodyClientHttpResponseWrapper.java:115) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.web.client.MessageBodyClientHttpResponseWrapper.hasMessageBody(MessageBodyClientHttpResponseWrapper.java:66) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:87) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:737) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:670) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.web.client.RestTemplate.postForObject(RestTemplate.java:414) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1700) ~[?:?]

Comment From: rstoyanchev

Yes it should not result in an NPE but the cause is likely a bug that should be addressed. What is the header data in such a case? Maybe that can help to reproduce it. Also any chance you could retry with 5.2.0.BULID-SNAPSHOT to confirm if it is related to #22821.

Comment From: membersound

The problem is: it only happens every other day, by chance. So if I'd be using the snapshot (which is not that easy as I'm totally inheriting from spring-boot release), I still can't be sure if it is fixed.

Unfortunately I did not find a way to reproduce the issue at will. The headers in those cases are nothing special: Headers: [X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY", Content-Type:"application/json;charset=UTF-8", Content-Length:"1430", Date:"Wed, 08 May 2019 11:55:22 GMT"]

Maybe it has to do with the fact the I'm sending and processing my requests in an async future?

@Autowired
private ThreadPoolExecutor executor;

List<Request> requests;

//the basic idea is to prepare all requests required, then dispatch all req async and collect the responses also async. then wait until all responses have been received.
List<CompletableFuture<Response>> futures = requests
        .stream()
        .map(req -> CompletableFuture.supplyAsync(
            () -> restTemplate.postForEntity(URL, req, Response.class).getBody(), executor)
        .collect(Collectors.toList());

List<Response> responses = futures.stream().map(CompletableFuture::join).collect(Collectors.toList());

I also found another log entry, that interestingly throws the NPE also inside an async process. It comes from the following code:

@Service
@Async
public class MyHeaderInterceptor() {
    public void traceHeaders(ClientHttpResponse rsp) {
        LOGGER.info(message.getHeaders().toString());
    }
}

Same issue: occasionally getting NPEs like:

java.lang.NullPointerException: null
    at org.springframework.util.CollectionUtils$MultiValueMapAdapter.add(CollectionUtils.java:460) ~[spring-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.http.HttpHeaders.add(HttpHeaders.java:1565) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.http.client.HttpComponentsClientHttpResponse.getHeaders(HttpComponentsClientHttpResponse.java:71) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.http.client.BufferingClientHttpResponseWrapper.getHeaders(BufferingClientHttpResponseWrapper.java:65) ~[spring-web-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at my.logging.MyHeaderInterceptor.traceHeaders(MyHeaderInterceptor.java:116) ~[classes/:?]
    at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:749) ~[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at org.springframework.aop.interceptor.AsyncExecutionInterceptor.lambda$invoke$0(AsyncExecutionInterceptor.java:115) ~[spring-aop-5.1.6.RELEASE.jar:5.1.6.RELEASE]
    at java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[?:?]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[?:?]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[?:?]
    at java.lang.Thread.run(Thread.java:834) [?:?]

To be complete, my RestTemplate is build with apache HttpClient as follows:

@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
    HttpClient httpClient = HttpClientBuilder.create()
            .setMaxConnTotal(200)
            .setMaxConnPerRoute(100)
            .build();

    HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient);
    factory.setConnectTimeout(2000);
    factory.setReadTimeout(10000);

    return builder.requestFactory(() -> new BufferingClientHttpRequestFactory(factory)).build();
}

Comment From: bclozel

We didn't get any new reports for this, I'm assuming this has been fixed with #22821.