Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quarkus Configuration Disambiguation strategy for environment variables fails in 3.17.0+ #46245

Open
ryandens opened this issue Feb 13, 2025 · 6 comments
Labels
area/config kind/bug Something isn't working

Comments

@ryandens
Copy link
Contributor

Describe the bug

The Quarkus configuration reference guide describes how to disambiguate configuration properties with dynamic segments. The recommended approach is to check in the expected configuration key with a value left empty to enable it to be configured via an environment variable.

Expected behavior

The server can start/tests can run without providing an optional entry for a dynamic configuration value.

Actual behavior

This behavior breaks on an upgrade from 3.16.4 to 3.17.0. I tested 3.18.3 and 3.19.0.CR1 to ensure this hasn't been fixed yet.

It fails with the following error in a Quarkus component test:

Configuration validation failed:
	java.util.NoSuchElementException: SRCFG00040: The config property com.ryandens.deployments."fake-deployment-name-1" is defined as the empty String ("") which the following Converter considered to be null: io.smallrye.config.Converters$BuiltInConverter
io.smallrye.config.ConfigValidationException: Configuration validation failed:
	java.util.NoSuchElementException: SRCFG00040: The config property com.ryandens.deployments."fake-deployment-name-1" is defined as the empty String ("") which the following Converter considered to be null: io.smallrye.config.Converters$BuiltInConverter
	at io.smallrye.config.SmallRyeConfig.buildMappings(SmallRyeConfig.java:139)
	at io.smallrye.config.SmallRyeConfig.<init>(SmallRyeConfig.java:93)
	at io.smallrye.config.SmallRyeConfigBuilder.build(SmallRyeConfigBuilder.java:773)
	at io.quarkus.test.component.QuarkusComponentTestExtension.startContainer(QuarkusComponentTestExtension.java:454)
	at io.quarkus.test.component.QuarkusComponentTestExtension.beforeEach(QuarkusComponentTestExtension.java:237)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	Suppressed: java.lang.NullPointerException: Cannot invoke "java.util.List.iterator()" because "injectedParams" is null
		at io.quarkus.test.component.QuarkusComponentTestExtension.destroyDependentTestMethodParams(QuarkusComponentTestExtension.java:349)
		at io.quarkus.test.component.QuarkusComponentTestExtension.afterEach(QuarkusComponentTestExtension.java:249)
		... 2 more

A similar error occurs with the Quarkus test

java.lang.RuntimeException: Failed to start quarkus
java.lang.RuntimeException: java.lang.RuntimeException: Failed to start quarkus
	at io.quarkus.test.junit.QuarkusTestExtension.throwBootFailureException(QuarkusTestExtension.java:611)
	at io.quarkus.test.junit.QuarkusTestExtension.interceptTestClassConstructor(QuarkusTestExtension.java:695)
	at java.base/java.util.Optional.orElseGet(Optional.java:364)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
Caused by: java.lang.RuntimeException: Failed to start quarkus
	at io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)
	at io.quarkus.runtime.Application.start(Application.java:101)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at io.quarkus.runner.bootstrap.StartupActionImpl.run(StartupActionImpl.java:305)
	at io.quarkus.test.junit.QuarkusTestExtension.doJavaStart(QuarkusTestExtension.java:224)
	at io.quarkus.test.junit.QuarkusTestExtension.ensureStarted(QuarkusTestExtension.java:578)
	at io.quarkus.test.junit.QuarkusTestExtension.beforeAll(QuarkusTestExtension.java:628)
	... 1 more
Caused by: io.smallrye.config.ConfigValidationException: Configuration validation failed:
	java.util.NoSuchElementException: SRCFG00040: The config property com.ryandens.deployments."fake-deployment-name-1" is defined as the empty String ("") which the following Converter considered to be null: io.smallrye.config.Converters$BuiltInConverter
	at io.smallrye.config.SmallRyeConfig.buildMappings(SmallRyeConfig.java:139)
	at io.smallrye.config.SmallRyeConfig.<init>(SmallRyeConfig.java:93)
	at io.smallrye.config.SmallRyeConfigBuilder.build(SmallRyeConfigBuilder.java:773)
	at io.quarkus.runtime.generated.Config.readConfig(Unknown Source)
	at io.quarkus.runtime.generated.Config.createRunTimeConfig(Unknown Source)
	at io.quarkus.deployment.steps.RuntimeConfigSetup.deploy(Unknown Source)
	... 8 more


Failed to start quarkus
java.lang.RuntimeException: Failed to start quarkus
	at io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)
	at io.quarkus.runtime.Application.start(Application.java:101)
	at java.base/java.lang.reflect.Method.invoke(Method.java:580)
	at io.quarkus.runner.bootstrap.StartupActionImpl.run(StartupActionImpl.java:305)
	at io.quarkus.test.junit.QuarkusTestExtension.doJavaStart(QuarkusTestExtension.java:224)
	at io.quarkus.test.junit.QuarkusTestExtension.ensureStarted(QuarkusTestExtension.java:578)
	at io.quarkus.test.junit.QuarkusTestExtension.beforeAll(QuarkusTestExtension.java:628)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
Caused by: io.smallrye.config.ConfigValidationException: Configuration validation failed:
	java.util.NoSuchElementException: SRCFG00040: The config property com.ryandens.deployments."fake-deployment-name-1" is defined as the empty String ("") which the following Converter considered to be null: io.smallrye.config.Converters$BuiltInConverter
	at io.smallrye.config.SmallRyeConfig.buildMappings(SmallRyeConfig.java:139)
	at io.smallrye.config.SmallRyeConfig.<init>(SmallRyeConfig.java:93)
	at io.smallrye.config.SmallRyeConfigBuilder.build(SmallRyeConfigBuilder.java:773)
	at io.quarkus.runtime.generated.Config.readConfig(Unknown Source)
	at io.quarkus.runtime.generated.Config.createRunTimeConfig(Unknown Source)
	at io.quarkus.deployment.steps.RuntimeConfigSetup.deploy(Unknown Source)
	... 8 more

How to Reproduce?

  1. Clone the reproducer: https://github.com/ryandens/quarkus-config-disambiguation-reproducer
  2. Run the build, seeing the error in the test report/build scan for the QuarkusComponentTest
  3. Run the build, seeing the error in the test report/build scan for the QuarkusTest
  4. Run ./gradlew :lib:quarkusDev, seeing that the app fails to start up and serve the API.

Output of uname -a or ver

Darwin mac

Output of java -version

openjdk version "21.0.6" 2025-01-21 LTS

Mandrel or GraalVM version (if different from Java)

No response

Quarkus version or git rev

3.18.3

Build tool (ie. output of mvnw --version or gradlew --version)

8.12.1

Additional information

No response

@ryandens ryandens added area/native-image kind/bug Something isn't working labels Feb 13, 2025
Copy link

quarkus-bot bot commented Feb 13, 2025

/cc @Karm (native-image), @galderz (native-image), @radcortez (config), @zakkak (native-image)

@ryandens
Copy link
Contributor Author

I believe this issue was incorrectly labeled with area/native-image - though area/config is, of course, appropriate.

@geoand
Copy link
Contributor

geoand commented Feb 13, 2025

cc @radcortez

@ryandens
Copy link
Contributor Author

I'm wondering, but am unsure, if this has something to do with the behavior change by an upgrade to SmallRye Config 3.10.0 done in 3.17.0.CR1 (quarkus PR: #42227). I skimmed the release notes, and nothing else jumped out at me. There are some in-depth discussions about empty config values in microprofile/microprofile-config#671 and microprofile/microprofile-config#446

@ryandens
Copy link
Contributor Author

I believe I found the suspect PR for the behavior change. It is in the smallrye upgrade to 3.10.0: smallrye/smallrye-config#1220

This PR adds a new construct to define a required list of keys for a Map like the one I use. I believe changing the behavior of the previously documented config disambiguation was an unintended consequence.

It seems to be tripping up on a call to ConfigMappingInterface.getDefaultValue() in the ConfigMappingGenerator, whereas previously there was a check for if the value was optional

@radcortez
Copy link
Member

I'll have a look.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/config kind/bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants