Skip to content

Diagnostics are poor when property resolution throws a ConversionFailedException #43378

Closed
@wilkinsona

Description

@wilkinsona

We call PropertyResolver#getProperty(name, type) in a few places. This method can throw a ConversionFailedException which results in a lengthy, and not very helpful, stack trace such as:

2024-12-03T16:21:40,628Z ERROR o.s.b.SpringApplication:857        Application run failed   java.lang.IllegalArgumentException: Invalid boolean value 'none'
        at org.springframework.core.convert.support.StringToBooleanConverter.convert(StringToBooleanConverter.java:55)
        at org.springframework.core.convert.support.StringToBooleanConverter.convert(StringToBooleanConverter.java:33)
        at org.springframework.core.convert.support.GenericConversionService$ConverterAdapter.convert(GenericConversionService.java:358)
        at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:41)
        ... 40 common frames omitted
Wrapped by: org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [java.lang.Boolean] for value [none]
        at org.springframework.core.convert.support.ConversionUtils.invokeConverter(ConversionUtils.java:47)
        at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:182)
        at org.springframework.core.convert.support.GenericConversionService.convert(GenericConversionService.java:165)
        at org.springframework.core.env.AbstractPropertyResolver.convertValueIfNecessary(AbstractPropertyResolver.java:281)
        at org.springframework.boot.context.properties.source.ConfigurationPropertySourcesPropertyResolver.getProperty(ConfigurationPropertySourcesPropertyResolver.java:82)
        at org.springframework.boot.context.properties.source.ConfigurationPropertySourcesPropertyResolver.getProperty(ConfigurationPropertySourcesPropertyResolver.java:66)
        at org.springframework.core.env.AbstractEnvironment.getProperty(AbstractEnvironment.java:568)
        at org.springframework.boot.actuate.autoconfigure.endpoint.PropertiesEndpointAccessResolver.determineDefaultAccess(PropertiesEndpointAccessResolver.java:65)
        at org.springframework.boot.actuate.autoconfigure.endpoint.PropertiesEndpointAccessResolver.<init>(PropertiesEndpointAccessResolver.java:58)
        at java.base/java.util.concurrent.ConcurrentMap.computeIfAbsent(ConcurrentMap.java:330)
        at org.springframework.boot.actuate.autoconfigure.endpoint.condition.OnAvailableEndpointCondition.getAccess(OnAvailableEndpointCondition.java:136)
        at org.springframework.boot.actuate.autoconfigure.endpoint.condition.OnAvailableEndpointCondition.getAccessOutcome(OnAvailableEndpointCondition.java:130)
        at org.springframework.boot.actuate.autoconfigure.endpoint.condition.OnAvailableEndpointCondition.getMatchOutcome(OnAvailableEndpointCondition.java:117)
        at org.springframework.boot.actuate.autoconfigure.endpoint.condition.OnAvailableEndpointCondition.getMatchOutcome(OnAvailableEndpointCondition.java:79)
        at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)
        ... 26 common frames omitted
Wrapped by: java.lang.IllegalStateException: Error processing condition on org.springframework.boot.actuate.autoconfigure.audit.AuditEventsEndpointAutoConfiguration
        at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:60)
        at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:99)
        at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:233)
        at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:603)
        ... 23 common frames omitted
Wrapped by: org.springframework.beans.factory.BeanDefinitionStoreException: Failed to process import candidates for configuration class : Error processing condition on org.springframework.boot.actuate.autoconfigure.audit.AuditEventsEndpointAutoConfiguration
        at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:613)
        at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.lambda$processGroupImports$1(ConfigurationClassParser.java:836)
        at java.base/java.lang.Iterable.forEach(Iterable.java:75)
        at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.processGroupImports(ConfigurationClassParser.java:833)
        at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorHandler.process(ConfigurationClassParser.java:803)
        at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:189)
        at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:418)
        at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:290)
        at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:349)
        at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:118)
        at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:791)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:609)
        at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:146)
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752)
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:439)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:318)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1361)
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1350)
        at Application.main(Application.java:16)
        at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
        at java.base/java.lang.reflect.Method.invoke(Method.java:580)
        at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:102)
        at org.springframework.boot.loader.launch.Launcher.launch(Launcher.java:64)
        at org.springframework.boot.loader.launch.JarLauncher.main(JarLauncher.java:40)

This could be improved by catching the ConversionFailedException and throwing an InvalidConfigurationPropertyValueException. The existing failure analysis will then kick in, turning the above into something more useful such as:

***************************
APPLICATION FAILED TO START
***************************

Description:

Invalid value 'none' for configuration property 'management.endpoints.enabled-by-default' (originating from 'System Environment Property "MANAGEMENT_ENDPOINTS_ENABLED_BY_DEFAULT"'). Validation failed for the following reason:

Failed to convert from type [java.lang.String] to type [java.lang.Boolean] for value [none]

Action:

Review the value of the property with the provided reason.

I'd like to discuss this with the team to see if we consider the current behavior to be a usability bug that should be fixed in a maintenance release or if this should be an enhancement for 3.5.x or later.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions