Skip to content

fix: keep a type on the rate limit headers under OpenAPI 3.1 - #2124

Merged
netomi merged 1 commit into
mainfrom
fix/openapi-header-schema-type
Sep 2, 2026
Merged

fix: keep a type on the rate limit headers under OpenAPI 3.1#2124
netomi merged 1 commit into
mainfrom
fix/openapi-header-schema-type

Conversation

@netomi

@netomi netomi commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

Accessing api-docs logs:

o.springdoc.core.utils.SpringDocUtils : Json Processing Exception occurred: Cannot construct instance
of `java.util.HashSet` (although at least one Creator exists): no String-argument constructor/factory
method to deserialize from String value ('integer')
 (through reference chain: io.swagger.v3.oas.models.media.JsonSchema["type"])

Chasing it turned up a second, silent problem in our own document. Both come from the same change.

What changed

46335e7 (#2112) bumped springdoc 2.8.13 to 3.1.0. springdoc 3.x defaults springdoc.api-docs.version to OPENAPI_3_1; 2.8.13 defaulted to OPENAPI_3_0. The emitted spec version flipped as a side effect of the bump.

The silent bug, fixed here

new Schema<>().type("integer") sets only the legacy string type and leaves the 3.1 types set null, and a 3.1 document does not serialize the former:

type()           write31={"format":"int32"}                     <- no type at all
IntegerSchema    write31={"type":"integer","format":"int32"}

So all four rate limit headers have been documented with no type since the upgrade. IntegerSchema populates both fields and is correct under either spec version, so this is fixed independently of which version we emit.

The logged warning

swagger-core 2.2.52's 3.1 mapper writes a single schema type as a bare string but only reads an array back:

IntegerSchema        write31={"type":"integer",...}            read31=FAIL (HashSet from String 'integer')
IntegerSchema+null   write31={"type":["integer","null"],...}   read31=OK

SpringDocUtils.cloneViaJson cannot re-read what it just wrote. It logs at warn and returns the original object instead of a copy, so api-docs still render — the cost is a shared schema instance where a clone was intended. A two-typed schema round-trips fine, which is why only some schemas trip it.

Nothing in this repository can fix that asymmetry, so the dev configuration pins api-docs back to openapi_3_0. That restores the document as it was before #2112 and silences the warning, since the 3.0 mapper is symmetric on string type. Verified the key actually binds — a mistyped property would bind silently — resolving to OPENAPI_3_0 / spec 3.0.1.

The pin is dev-only, as requested. Deployments that want it will need it in their own configuration; deploy/openshift/application.yml and deploy/docker/configuration/application.yml are untouched.

Tests

shouldGiveTheRateLimitHeadersATypeInEitherSpecVersion asserts the header schema serializes with "type":"integer" under both the 3.0 and 3.1 mappers, so it holds whichever version springdoc defaults to next. Fail-first checked: red with new Schema<>().type(...) restored.

Full server suite passes, 1132 tests.

🤖 Generated with Claude Code

Upgrading springdoc to 3.1.0 (#2112) also changed the spec version it emits:
springdoc 3.x defaults springdoc.api-docs.version to OPENAPI_3_1, where 2.8.13
defaulted to OPENAPI_3_0. That was a side effect of the bump rather than a
decision, and it silently dropped a field from the document.

new Schema<>().type("integer") sets only the legacy string `type` and leaves the
3.1 `types` set null, and a 3.1 document does not serialize the former. The four
rate limit headers have therefore been documented with no type at all since the
upgrade. Building them through IntegerSchema populates both fields, so they keep
a type whichever version springdoc emits.

The dev configuration pins api-docs back to 3.0. Beyond restoring the document
as it was, it silences a warning that OpenAPI 3.1 draws out of swagger-core
2.2.52 on every schema springdoc clones:

  SpringDocUtils : Json Processing Exception occurred: Cannot construct instance
  of `java.util.HashSet` [...] from String value ('integer')
  (through reference chain: io.swagger.v3.oas.models.media.JsonSchema["type"])

Its 3.1 mapper writes a single type as a bare string but only reads an array
back, so cloneViaJson cannot re-read what it just wrote. It logs and falls back
to the original object, so the document still renders. A schema with two types
serializes as an array and round-trips fine, which is why only some schemas trip
it. Nothing in this repository can fix that asymmetry; only avoiding 3.1 avoids
it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@netomi
netomi merged commit 209bc6b into main Sep 2, 2026
5 checks passed
@netomi
netomi deleted the fix/openapi-header-schema-type branch September 2, 2026 06:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant