When a YAML configuration using explicit type tags is loaded, org.yaml.snakeyaml.constructor.ConstructorException is thrown.

Spring Boot version: 2.2.6.RELEASE JDK 8 and 11 produces the same issue Used to work with 1.5.1.RELEASE

Example YAML configuration:

exampleConfig:
    example: !!example.DefaultExampleType
        property: 'test'

The issue occurs when property: 'test' is converted, which should be a String.

This is the exception stack trace:

java.lang.IllegalStateException: Failed to load property source from location 'classpath:/application.yml'
    at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:545)
    at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.loadForFileExtension(ConfigFileApplicationListener.java:494)
    at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:464)
    at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.lambda$null$7(ConfigFileApplicationListener.java:443)
    at java.base/java.lang.Iterable.forEach(Iterable.java:75)
    at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.lambda$load$8(ConfigFileApplicationListener.java:443)
    at java.base/java.lang.Iterable.forEach(Iterable.java:75)
    at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:440)
    at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.lambda$load$0(ConfigFileApplicationListener.java:335)
    at org.springframework.boot.context.config.FilteredPropertySource.apply(FilteredPropertySource.java:54)
    at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:323)
    at org.springframework.boot.context.config.ConfigFileApplicationListener.addPropertySources(ConfigFileApplicationListener.java:214)
    at org.springframework.boot.context.config.ConfigFileApplicationListener.postProcessEnvironment(ConfigFileApplicationListener.java:198)
    at org.springframework.boot.context.config.ConfigFileApplicationListener.onApplicationEnvironmentPreparedEvent(ConfigFileApplicationListener.java:188)
    at org.springframework.boot.context.config.ConfigFileApplicationListener.onApplicationEvent(ConfigFileApplicationListener.java:176)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.doInvokeListener(SimpleApplicationEventMulticaster.java:172)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.invokeListener(SimpleApplicationEventMulticaster.java:165)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:139)
    at org.springframework.context.event.SimpleApplicationEventMulticaster.multicastEvent(SimpleApplicationEventMulticaster.java:127)
    at org.springframework.boot.context.event.EventPublishingRunListener.environmentPrepared(EventPublishingRunListener.java:76)
    at org.springframework.boot.SpringApplicationRunListeners.environmentPrepared(SpringApplicationRunListeners.java:53)
    at org.springframework.boot.SpringApplication.prepareEnvironment(SpringApplication.java:345)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:308)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1226)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1215)
    at example.YamlExampleApplication.loadSpringBoot(YamlExampleApplication.java:84)
    at example.YamlExampleApplication.main(YamlExampleApplication.java:48)
Caused by: org.yaml.snakeyaml.constructor.ConstructorException: Cannot create property=property for JavaBean=DefaultMatcher{property=null}
 in 'reader', line 3, column 14:
        example: !!example.DefaultExampleType
                 ^
argument type mismatch
 in 'reader', line 4, column 19:
            property: 'test'
                      ^

    at org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.constructJavaBean2ndStep(Constructor.java:270)
    at org.yaml.snakeyaml.constructor.Constructor$ConstructMapping.construct(Constructor.java:149)
    at org.yaml.snakeyaml.constructor.Constructor$ConstructYamlObject.construct(Constructor.java:309)
    at org.yaml.snakeyaml.constructor.BaseConstructor.constructObjectNoCheck(BaseConstructor.java:216)
    at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:205)
    at org.springframework.boot.env.OriginTrackedYamlLoader$OriginTrackingConstructor.constructObject(OriginTrackedYamlLoader.java:94)
    at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping2ndStep(BaseConstructor.java:465)
    at org.yaml.snakeyaml.constructor.SafeConstructor.constructMapping2ndStep(SafeConstructor.java:184)
    at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping(BaseConstructor.java:446)
    at org.yaml.snakeyaml.constructor.SafeConstructor$ConstructYamlMap.construct(SafeConstructor.java:521)
    at org.yaml.snakeyaml.constructor.BaseConstructor.constructObjectNoCheck(BaseConstructor.java:216)
    at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:205)
    at org.springframework.boot.env.OriginTrackedYamlLoader$OriginTrackingConstructor.constructObject(OriginTrackedYamlLoader.java:94)
    at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping2ndStep(BaseConstructor.java:465)
    at org.yaml.snakeyaml.constructor.SafeConstructor.constructMapping2ndStep(SafeConstructor.java:184)
    at org.yaml.snakeyaml.constructor.BaseConstructor.constructMapping(BaseConstructor.java:446)
    at org.yaml.snakeyaml.constructor.SafeConstructor$ConstructYamlMap.construct(SafeConstructor.java:521)
    at org.yaml.snakeyaml.constructor.BaseConstructor.constructObjectNoCheck(BaseConstructor.java:216)
    at org.yaml.snakeyaml.constructor.BaseConstructor.constructObject(BaseConstructor.java:205)
    at org.springframework.boot.env.OriginTrackedYamlLoader$OriginTrackingConstructor.constructObject(OriginTrackedYamlLoader.java:94)
    at org.yaml.snakeyaml.constructor.BaseConstructor.constructDocument(BaseConstructor.java:164)
    at org.yaml.snakeyaml.constructor.BaseConstructor.getData(BaseConstructor.java:129)
    at org.yaml.snakeyaml.Yaml$1.next(Yaml.java:548)
    at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:160)
    at org.springframework.beans.factory.config.YamlProcessor.process(YamlProcessor.java:134)
    at org.springframework.boot.env.OriginTrackedYamlLoader.load(OriginTrackedYamlLoader.java:75)
    at org.springframework.boot.env.YamlPropertySourceLoader.load(YamlPropertySourceLoader.java:50)
    at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.loadDocuments(ConfigFileApplicationListener.java:562)
    at org.springframework.boot.context.config.ConfigFileApplicationListener$Loader.load(ConfigFileApplicationListener.java:518)
    ... 26 common frames omitted
Caused by: java.lang.IllegalArgumentException: argument type mismatch
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

The original cause is java.lang.IllegalArgumentException: argument type mismatch. It is thrown because the type of value test of property: 'test' is not converted to String, but remains OriginTrackedValue$OriginTrackedCharSequence.

I have created an example project showcasing this. It also shows how the YAML files are parsed by SnakeYAML if manually loaded and not by the Spring Boot auto configuration.

Unsure if related to #8540.

Comment From: philwebb

21596 has recently been applied to further restrict the use of custom types as a security precaution so it may not be possible to make things work in same way as they did in 1.5.

@kappmeier Can you explain a bit more about your use-case? We need to be able to ultimately map a YAML document to a flat PropertySource and we didn't anticipate custom types would be used.

Comment From: spring-projects-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: kappmeier

I create a list of matchers. The matcher type is an interface, but there are multiple implementing classes, and as far as I know I have to provide the exact type.

If this is forbidden in the future there will certainly be ways to initialize the object in a different way.

Regarding #21596 it is at least a good thing to throw some kind of error explaining that certain YAML features are not supported.

Comment From: wilkinsona

Thanks for your patience. How do you expect your custom types to be mapped to entries in a property source and then potentially bound to a @ConfigurationProperties class? Perhaps you could share a small sample that reproduces the failure and illustrates what you're trying to do?

Comment From: spring-projects-issues

If you would like us to look at this issue, please provide the requested information. If the information is not provided within the next 7 days this issue will be closed.

Comment From: spring-projects-issues

Closing due to lack of requested feedback. If you would like us to look at this issue, please provide the requested information and we will re-open the issue.