Hello, I am working on a project using Spring Boot 3.4.0. I defined List environment variables, but I encountered a binding error.

Here is my code and the error log:

// application.yml
kis:
  domain: ${KIS_DOMAIN:domain}
  appkey:
  - ${KIS_APPKEY_1:appkey}
  - ${KIS_APPKEY_2:appkey}
  appsecret:
  - ${KIS_APPSECRET_1:appsecret}
  - ${KIS_APPSECRET_2:appsecret}
  web-socket-domain: ${KIS_WEBSOCKET_DOMAIN:domain}
// KisProperties.java
@Component
@ConfigurationProperties(prefix = "kis")
@Getter
@Setter
@ToString
public class KisProperties {
    private String domain;
    private String webSocketDomain;
    private List<String> appkey;
    private List<String> appsecret;

   ...
}
Description:

Binding to target [Bindable@651a3e01 type = java.util.List<java.lang.String>, value = 'provided', annotations = array<Annotation>[[empty]], bindMethod = [null]] failed:

    Property: kis.appkey[1]
    Value: "===hidden==="
    Origin: System Environment Property "KIS_APPKEY_1"
    Reason: The elements [kis.appkey[1],kis.appkey[2]] were left unbound.
    Property: kis.appkey[2]
    Value: "===hidden==="
    Origin: System Environment Property "KIS_APPKEY_2"
    Reason: The elements [kis.appkey[1],kis.appkey[2]] were left unbound.

Action:

Update your application's configuration

I resolved the issue by changing the environment variable names.

// application.yml
kis:
  domain: ${KIS_DOMAIN:domain}
  appkey:
  - ${KIS_APPKEY_0:appkey}  # 1 → 0
  - ${KIS_APPKEY_1:appkey}  # 2 → 1
  appsecret:
  - ${KIS_APPSECRET_0:appsecret}  # 1 → 0
  - ${KIS_APPSECRET_1:appsecret}  # 2 → 1
  web-socket-domain: ${KIS_WEBSOCKET_DOMAIN:domain}

I believe the error occurred because the environment variable names ended with _1, which led to them being bound as [1].

According to the official documentation, the variable names should be wrapped in underscores with numbers to be properly bound.

"Environment variables can also be used when binding to object lists. To bind to a List, the element number should be surrounded with underscores in the variable name." - SpringBoot 3.3.9 and SpringBoot 3.4.3 Documentation

However, in my case, KIS_APPKEY_1, KIS_APPKEY_2 were bound as KIS_APPKEY_[1], KIS_APPKEY_[2], resulting in a binding error.

To test this issue, I used Spring Boot 3.4.3 with the same configuration, and it executed successfully.

I am curious why this error occurs only in 3.4.0 and why Spring Boot 3.3.9 and 3.4.3 behave differently, even though the official documentation regarding environment variable binding is the same for both versions.

Comment From: nosan

Hi @hky035,

I tried reproducing this issue with 3.3.9 and 3.4.3, but both versions failed with the same error. Did I miss something?

KIS_APPKEY_2=APPKEY_2
KIS_APPKEY_1=APPKEY_1

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::                (v3.3.9)

2025-03-03T16:30:22.996+02:00  INFO 6800 --- [           main] task.gh44508.Gh44508Application          : Starting Gh44508Application using Java 17.0.13 with PID 6800 (/Users/dmytronosan/IdeaProjects/gh-44508/build/classes/java/main started by dmytronosan in /Users/dmytronosan/IdeaProjects/gh-44508)
2025-03-03T16:30:22.997+02:00  INFO 6800 --- [           main] task.gh44508.Gh44508Application          : No active profile set, falling back to 1 default profile: "default"
2025-03-03T16:30:23.119+02:00  WARN 6800 --- [           main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.boot.context.properties.ConfigurationPropertiesBindException: Error creating bean with name 'kis-task.gh44508.KisProperties': Could not bind properties to 'KisProperties' : prefix=kis, ignoreInvalidFields=false, ignoreUnknownFields=true
2025-03-03T16:30:23.122+02:00  INFO 6800 --- [           main] .s.b.a.l.ConditionEvaluationReportLogger : 

Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2025-03-03T16:30:23.127+02:00 ERROR 6800 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

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

Description:

Binding to target [Bindable@16fe9c29 type = java.util.List<java.lang.String>, value = 'provided', annotations = array<Annotation>[[empty]], bindMethod = [null]] failed:

    Property: kis.appkey[1]
    Value: "APPKEY_1"
    Origin: System Environment Property "KIS_APPKEY_1"
    Reason: The elements [kis.appkey[1],kis.appkey[2]] were left unbound.
    Property: kis.appkey[2]
    Value: "APPKEY_2"
    Origin: System Environment Property "KIS_APPKEY_2"
    Reason: The elements [kis.appkey[1],kis.appkey[2]] were left unbound.

Action:

Update your application's configuration

I am curious why this error occurs only in 3.4.0 and why Spring Boot 3.3.9 and 3.4.3 behave differently, even though the official documentation regarding environment variable binding is the same for both versions.

Could you please provide a sample to reproduce this issue? Based on your comment, it behaves differently in 3.3.9 compared to 3.4.x.

Thanks

Comment From: hky035

Thanks for your comment, @nosan

Here is a sample project that I used. KisProperties and application.yml are the same as in the description. (I apologize if I couldn't provide the sample accurately because I'm not very good at English.

// build.gradle
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'com.mysql:mysql-connector-j'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}

After clearing the cache and testing, I encountered the same error in Spring Boot 3.4.3.

Additionally, I was curious if there might be an issue related to the number of underscores or variable names, so I conducted several tests. In the end, I believe I found the root cause of the problem.

I thought that environment variables could only be injected through the application.~~~ files, regardless of how they were set. However, when using @ConfigurationProperties, the environment variables can be injected automatically due to Relaxed Binding, even if only the environment variables are set.

To test this, I modified the code as follows and ran the test.

// application.yml
kis:
  domain: ${KIS_DOMAIN:domain}
#  appkey:
#  - ${KIS_APPKEY_1:appkey}
#  - ${KIS_APPKEY_2:appkey}
#  appsecret:
#  - ${KIS_APPSECRET_1:appsecret}
#  - ${KIS_APPSECRET_2:appsecret}
  web-socket-domain: ${KIS_WEBSOCKET_DOMAIN:domain}
// Environment Variable
KIS_APPKEY_1=appkey
KIS_APPKEY_2=appkey

The result of above test is Fail.

// application.yml
kis:
  domain: ${KIS_DOMAIN:domain}
#  appkey:
#  - ${KIS_APPKEY_1:appkey}
#  - ${KIS_APPKEY_2:appkey}
#  appsecret:
#  - ${KIS_APPSECRET_1:appsecret}
#  - ${KIS_APPSECRET_2:appsecret}
  web-socket-domain: ${KIS_WEBSOCKET_DOMAIN:domain}
// Environment Variable
KIS_APPKEY_0=appkey
KIS_APPKEY_1=appkey

The result of this test is Success.

So, I think that the problem is Relaxed Binding.

The class annotated with @ConfigurationProperties automatically looks for injectable values from sources like application.yml or environment variables. In this case, it finds the environment variable that matches kis.appkey and binds it, but the issue arises because the indices do not match. ( kis.appkey[1], kis.appkey[2] )

It seems that this assumption is correct, as changing the environment variable names to not match the field names defined in @ConfigurationProperties, or altering the key names in the application.yml file allows it to function properly.

Thank you once again for your comments.

Comment From: nosan

I am a bit confused at the moment. Your initial statement was that something worked in 3.3.9 and stopped working (or behaves differently) in 3.4.x. However, I verified that the error you described occurred in 3.3.9 (and even in 3.0.0) as well.

The behavior you described regarding Relaxed Binding has existed in Spring Boot since 2.0.0, if I am not mistaken.

It is well-documented here: - Relaxed Binding 2.0 - Binding From Environment Variables

The configuration properties order is documented here: - Configuration Properties Order

Either I am mistaken, or there isn’t an issue. If you still believe there is an issue, a minimal example demonstrating that something worked in 3.3.9 but stopped working (or behaves differently) in 3.4.x is very needed.

You can use https://start.spring.io/ to generate a new project.

Thanks

KIS_APPKEY_2=APPKEY_2
KIS_APPKEY_1=APPKEY_1

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v3.0.0)

2025-03-03T19:44:39.821+02:00  INFO 9636 --- [           main] task.gh44508.Gh44508Application          : Starting Gh44508Application using Java 17.0.13 with PID 9636 (/Users/dmytronosan/IdeaProjects/gh-44508/build/classes/java/main started by dmytronosan in /Users/dmytronosan/IdeaProjects/gh-44508)
2025-03-03T19:44:39.822+02:00  INFO 9636 --- [           main] task.gh44508.Gh44508Application          : No active profile set, falling back to 1 default profile: "default"
2025-03-03T19:44:39.940+02:00  WARN 9636 --- [           main] s.c.a.AnnotationConfigApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.boot.context.properties.ConfigurationPropertiesBindException: Error creating bean with name 'kisProperties': Could not bind properties to 'KisProperties' : prefix=kis, ignoreInvalidFields=false, ignoreUnknownFields=true
2025-03-03T19:44:39.943+02:00  INFO 9636 --- [           main] .s.b.a.l.ConditionEvaluationReportLogger : 

Error starting ApplicationContext. To display the condition evaluation report re-run your application with 'debug' enabled.
2025-03-03T19:44:39.948+02:00 ERROR 9636 --- [           main] o.s.b.d.LoggingFailureAnalysisReporter   : 

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

Description:

Binding to target [Bindable@1e411d81 type = java.util.List<java.lang.String>, value = 'provided', annotations = array<Annotation>[[empty]]] failed:

    Property: kis.appkey[1]
    Value: "APPKEY_1"
    Origin: System Environment Property "KIS_APPKEY_1"
    Reason: The elements [kis.appkey[1],kis.appkey[2]] were left unbound.
    Property: kis.appkey[2]
    Value: "APPKEY_2"
    Origin: System Environment Property "KIS_APPKEY_2"
    Reason: The elements [kis.appkey[1],kis.appkey[2]] were left unbound.

Action:

Update your application's configuration