spring-projects / spring-projects/spring-vault

VaultHealthImpl cannot deserialize sys/health when performance_standby is absent

Open Beginner friendly
#1,048 1 comment 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
306
Forks
202
PR merge metrics
No merged PRs in 30d

Description

Summary

VaultSysTemplate.VaultHealthImpl takes performance_standby as a primitive boolean creator parameter. If the server response omits that field, deserialization fails instead of defaulting to false.

OpenBao removed performance_standby from GET /sys/health in 2.6.0, so every health check against OpenBao 2.6.0 or later throws.

Stack trace
o.s.c.v.c.VaultReactiveHealthIndicator : Health check failed

org.springframework.core.codec.DecodingException: JSON decoding error: Cannot map `null` into type `boolean`
(set `DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES` to 'false' to allow)
	at org.springframework.http.codec.AbstractJacksonDecoder.processException(AbstractJacksonDecoder.java:261)
	*__checkpoint ⇢ Body from GET https://openbao.example.com:8200/v1/sys/health [DefaultClientResponse]
Caused by: tools.jackson.databind.exc.MismatchedInputException: Cannot map `null` into type `boolean`
 (through reference chain: org.springframework.vault.core.VaultSysTemplate$VaultHealthImpl["performance_standby"])
	at tools.jackson.databind.DeserializationContext.handleNullForPrimitives(DeserializationContext.java:1467)
	at tools.jackson.databind.deser.bean.PropertyValueBuffer._findMissing(PropertyValueBuffer.java:298)

The path through PropertyValueBuffer._findMissing shows this is an absent property rather than an explicit JSON null.

Why it surfaces now

Two independent changes combine.

  1. OpenBao 2.6.0 stopped returning performance_standby. The field described the Vault Enterprise performance standby concept, which OpenBao is retiring in favour of all standby nodes serving reads. Their own client struct in api/sys_health.go keeps the field with the comment // not present in OpenBao, but left here for compatibility.
  2. Jackson 3 enables FAIL_ON_NULL_FOR_PRIMITIVES by default. Under Jackson 2 an absent primitive quietly became false, which is why this never showed up before Spring Boot 4.

@JsonIgnoreProperties(ignoreUnknown = true) on VaultHealthImpl covers unexpected extra fields, not missing ones, so it does not help here.

Of the creator parameters, performance_standby is the only one affected. initialized, sealed, standby and server_time_utc are still returned, and replication_dr_mode is a nullable String that is already handled.

Reproduce
docker run -d -p 8200:8200 -e BAO_DEV_ROOT_TOKEN_ID=root openbao/openbao:2.6.2 server -dev -dev-listen-address=0.0.0.0:8200
curl -s http://127.0.0.1:8200/v1/sys/health

Response, with no performance_standby key:

{"initialized":true,"sealed":false,"standby":false,"replication_performance_mode":"disabled","replication_dr_mode":"disabled","server_time_utc":1788552096,"version":"2.6.2","cluster_name":"vault-cluster-8e617dcd","cluster_id":"92429cc1-b8f7-1c2b-a304-abf12923a5a2"}

The same command against openbao/openbao:2.5.4 includes "performance_standby":false and works fine.

Impact

VaultReactiveHealthIndicator and VaultHealthIndicator report DOWN with a decoding error rather than a health state. Where a Kubernetes liveness probe points at the aggregate /actuator/health, this restarts pods in a loop even though the application is running normally and has already read all of its secrets.

Suggested fix

Make performanceStandby a boxed Boolean, or otherwise let an absent performance_standby map to false. The value only feeds isPerformanceStandby(), and a server that does not report the field has no performance standby state to report.

Not a duplicate of #397 or #501

Both of those concern Vault Enterprise nodes that are performance standbys and return HTTP 473, and #397 was resolved as a synchronous RestTemplate error handling bug fixed in Spring Framework 5.2.5. This is the opposite situation: the field is absent on a healthy active node returning HTTP 200, and it reproduces on the reactive indicator, which #397 records as unaffected.

Versions
Component Version
Spring Boot 4.1.0
Spring Cloud 2025.1.2
spring-cloud-vault-config 5.0.2
spring-vault-core 4.0.3
jackson-databind 3.1.4
OpenBao 2.6.0, 2.6.1, 2.6.2
Java 25

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with VaultSysTemplate.VaultHealthImpl and its performance_standby creator parameter. Reproduce against OpenBao 2.6.2 using the provided Docker and curl commands, then verify that the health response deserializes successfully and VaultReactiveHealthIndicator and VaultHealthIndicator no longer report a decoding error when the field is absent.

Written by the indexing model from the issue text.

Assessment

Tech stack
java, spring
Domain
api, backend
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.