1) Empty array causes NPE in Spring Cloud config

2) Spring cloud config does not log the exception.

We use config-service. Spring Cloud version 2.1 used to work well. When we updated Spring Cloud version 2.2, it stopped working.

I use Spring profile native and fetch configuration from local file on dev machine (not from git repository).

This is an example of a configuration file in spring config. python-service.yml

resources:
  - resource1
  - resource2

newResources: []

The problem is caused by newResources: []. However, it worked in Spring Cloud v 2.1. Examples, I used curl and Postman. HTTP http://localhost:8888/python-service/dev Accept: application/vnd.spring-cloud.config-server.v2+json returns fail result 1).

{
    "timestamp": "2020-04-24T08:38:19.803+0000",
    "status": 500,
    "error": "Internal Server Error",
    "message": "Could not construct context for config=python-service profile=dev label=null includeOrigin=true; nested exception is java.lang.NullPointerException",
    "path": "/python-service/dev"
}

Next, without the Accept header, it works. HTTP http://localhost:8888/python-service/dev Returns success result 2).

{
    "name": "python-service",
    "profiles": [
        "dev"
    ],
    "label": null,
    "version": null,
    "state": null,
    "propertySources": [
        {
            "name": "file:/configuration/python-service.yml",
            "source": {
                "resources[0]": "resource1",
                "resources[1]": "resource2",
                "newResources": ""
            }
        }
    ]
}

By the way, why "newResources": "" is an empty String, if it was an array.

However, the header Accept: application/vnd.spring-cloud.config-server.v2+json is sent by Spring Cloud config client (unfortunately, I had to debug it!). In the version 2.1, there is Accept: application/json

As you see, different value for Accept header.

Next, when I down-graded Spring Cloud 2.1 It works http://localhost:8888/python-service/dev Accept: application/json Success result 2).

When I use Spring Cloud config-service version 2.2 and remove empty array from python-service.yml on local machine, it works as well. http://localhost:8888/python-service/dev returns success result 3)

{
    "name": "python-service",
    "profiles": [
        "dev"
    ],
    "label": null,
    "version": null,
    "state": null,
    "propertySources": [
        {
            "name": "file:/configuration/python-service.yml",
            "source": {
                "resources[0]": {
                    "value": "resource1",
                    "origin": "2:5"
                },
                "resources[1]": {
                    "value": "resource2",
                    "origin": "3:5"
                }
            }
        }
    ]
}

I do not know what origin: "3.5" is though. Please, advise.

How to support empty array in the configuration. It breaks our services.

Links https://github.com/spring-cloud/spring-cloud-config/issues/866 https://github.com/spring-projects/spring-boot/issues/12965 https://github.com/spring-projects/spring-framework/issues/21310

Comment From: spencergibb

Please provide the stack trace

Comment From: yan-khonski-it

I do not have stack trace. The problem is that when config-service fails, there are not logs in the config service. I have not debugged config-service; I debugged config service client.

Comment From: spencergibb

can you look on the config server?

Comment From: yan-khonski-it

please, give me one hour. I will check...

Comment From: yan-khonski-it

2020-04-24 15:10:58.756 DEBUG 1 --- [io-8888-exec-10] o.s.web.servlet.DispatcherServlet        : GET "/python-service/dev", parameters={}
2020-04-24 15:10:58.761 DEBUG 1 --- [io-8888-exec-10] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped to org.springframework.cloud.config.server.environment.EnvironmentController#defaultLabelIncludeOrigin(String, String)
2020-04-24 15:10:59.123 DEBUG 1 --- [io-8888-exec-10] .m.m.a.ExceptionHandlerExceptionResolver : Using @ExceptionHandler org.springframework.cloud.config.server.environment.EnvironmentController#environmentException(HttpServletResponse, EnvironmentException)
2020-04-24 15:10:59.126 DEBUG 1 --- [io-8888-exec-10] .m.m.a.ExceptionHandlerExceptionResolver : Resolved [org.springframework.cloud.config.server.environment.FailedToConstructEnvironmentException: Could not construct context for config=python-service profile=dev label=null includeOrigin=true; nested exception is java.lang.NullPointerException]
2020-04-24 15:10:59.138 DEBUG 1 --- [io-8888-exec-10] o.s.web.servlet.DispatcherServlet        : Completed 500 INTERNAL_SERVER_ERROR
2020-04-24 15:10:59.140 DEBUG 1 --- [io-8888-exec-10] o.s.web.servlet.DispatcherServlet        : "ERROR" dispatch for GET "/error", parameters={}

This a debug log.

Comment From: spencergibb

I'm unable to reproduce the issue.

Can you provide a complete, minimal, verifiable sample that reproduces the problem? It should be available as a GitHub (or similar) project or attached to this issue as a zip file.

Comment From: yan-khonski-it

Yes, I can make an example, but later. For now, the NPE was caused by org.springframework.cloud.config.server.environment.FailedToConstructEnvironmentException

Comment From: yan-khonski-it

More stack trace

org.springframework.cloud.config.server.environment.FailedToConstructEnvironmentException: Could not construct context for config=python-service profile=dev label=null includeOrigin=true; nested exception is java.lang.NullPointerException
    at org.springframework.cloud.config.server.environment.NativeEnvironmentRepository.findOne(NativeEnvironmentRepository.java:161)
    at org.springframework.cloud.config.server.environment.FailedToConstructEnvironmentException.<init>(FailedToConstructEnvironmentException.java:31)
    at org.springframework.cloud.config.server.environment.NativeEnvironmentRepository.findOne(NativeEnvironmentRepository.java:161)
    at org.springframework.cloud.config.server.environment.CompositeEnvironmentRepository.findOne(CompositeEnvironmentRepository.java:58)
    at org.springframework.cloud.config.server.environment.EnvironmentEncryptorEnvironmentRepository.findOne(EnvironmentEncryptorEnvironmentRepository.java:61)
    at org.springframework.cloud.config.server.environment.EnvironmentController.getEnvironment(EnvironmentController.java:144)
    at org.springframework.cloud.config.server.environment.EnvironmentController.defaultLabelIncludeOrigin(EnvironmentController.java:115)
    at jdk.internal.reflect.GeneratedMethodAccessor65.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282)
    at org.springframework.cloud.context.scope.GenericScope$LockedScopedProxyFactoryBean.invoke(GenericScope.java:499)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:747)
    at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:689)
    at org.springframework.cloud.config.server.environment.EnvironmentController$$EnhancerBySpringCGLIB$$38d99eeb.defaultLabelIncludeOrigin(<generated>)
    at jdk.internal.reflect.GeneratedMethodAccessor65.invoke(Unknown Source)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:106)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:888)
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793)
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:108)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
    at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:367)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:860)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1598)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.NullPointerException
    at org.springframework.cloud.config.server.environment.PassthruEnvironmentRepository.getMap(PassthruEnvironmentRepository.java:101)
    at org.springframework.cloud.config.server.environment.PassthruEnvironmentRepository.findOne(PassthruEnvironmentRepository.java:80)
    at org.springframework.cloud.config.server.environment.NativeEnvironmentRepository.findOne(NativeEnvironmentRepository.java:152)
    ... 68 more

Comment From: yan-khonski-it

debug-config-service-1

Comment From: yan-khonski-it

As I promised, I added logs. Next week, I will make a docker compose example for you to reproduce. Have a good weekend for now!@

Comment From: yan-khonski-it

Hi Please, check this repository https://github.com/yan-khonski-it/spring-cloud-config-demo

README.md file explains how to start the example. Use maven and Java 11 to build the project. Use docker to run it.

Comment From: ryanjbaxter

Why do we need to use docker compose to reproduce this? Does the JDK version make a difference? Why are you not using the Spring Cloud BOM?

Comment From: spencergibb

Duplicates #1572