Skip to content

NullPointerException when oneOf changes to anyOf in response schema #381

Description

@georgyangelov

I observed a NullPointerException when a response schema changes from using oneOf to anyOf. Here is a test that reproduces the issue.

The error is as follows:

java.lang.NullPointerException: Cannot invoke "java.util.List.iterator()" because the return value of "io.swagger.v3.oas.models.media.ComposedSchema.getOneOf()" is null

	at org.openapitools.openapidiff.core.compare.schemadiffresult.ComposedSchemaDiffResult.getMapping(ComposedSchemaDiffResult.java:120)
	at org.openapitools.openapidiff.core.compare.schemadiffresult.ComposedSchemaDiffResult.diff(ComposedSchemaDiffResult.java:68)
	at org.openapitools.openapidiff.core.compare.SchemaDiff.computeDiffForReal(SchemaDiff.java:354)
	at org.openapitools.openapidiff.core.compare.SchemaDiff.computeDeferredDiff(SchemaDiff.java:330)
	at org.openapitools.openapidiff.core.compare.SchemaDiff.diff(SchemaDiff.java:309)
	at org.openapitools.openapidiff.core.compare.SchemaDiff.diff(SchemaDiff.java:301)
	at org.openapitools.openapidiff.core.compare.ContentDiff.lambda$diff$1(ContentDiff.java:44)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1625)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:762)
	at org.openapitools.openapidiff.core.compare.ContentDiff.diff(ContentDiff.java:32)
	at org.openapitools.openapidiff.core.compare.ResponseDiff.computeDiff(ResponseDiff.java:60)
	at org.openapitools.openapidiff.core.compare.ResponseDiff.computeDiff(ResponseDiff.java:16)
	at org.openapitools.openapidiff.core.compare.ReferenceDiffCache.cachedDiff(ReferenceDiffCache.java:52)
	at org.openapitools.openapidiff.core.compare.ResponseDiff.diff(ResponseDiff.java:42)
	at org.openapitools.openapidiff.core.compare.ApiResponseDiff.diff(ApiResponseDiff.java:35)
	at org.openapitools.openapidiff.core.compare.OperationDiff.diff(OperationDiff.java:91)
	at org.openapitools.openapidiff.core.compare.PathDiff.diff(PathDiff.java:39)
[...]

The direct reason seems to be that in ComposedSchemaDiffResult#diff there is this check:

if (CollectionUtils.isNotEmpty(leftComposedSchema.getOneOf())
          || CollectionUtils.isNotEmpty(rightComposedSchema.getOneOf())) {

and later, in getMapping(rightComposedSchema) it's assumed that both left and right contain oneOf, which is incorrect as the check here is an OR instead of an AND.

Changing || to && fixes this particular issue and the tests pass, however I'm not certain that this is the correct fix as I don't understand the logic enough to be able to tell if I'm not breaking anything else.

Additionally, the way that anyOf is handled seems to be merging all schema alternatives into one, which includes merging their required options, which seems incorrect. If a schema is anyOf(A, B), where A has required property propA and B has required property propB, after the merge the result would be a schema that requires both propA and propB instead of propA OR propB.

Do you think that the || to && is a valid fix for the issue, or should the anyOf handling be changed somehow?

Activity

  1. bors2908 commented on Feb 23, 2026

    @bors2908

    Experienced the same issue:

    While comparing two schemas with maven plugin, one file had absent oneOf, other had it present, so it happily went through
    if (CollectionUtils.isNotEmpty(leftComposedSchema.getOneOf()) || CollectionUtils.isNotEmpty(rightComposedSchema.getOneOf())) {

    And failed with NPE in org.openapitools.openapidiff.core.compare.schemadiffresult.ComposedSchemaDiffResult#getMapping:
    for (Schema<?> schema : composedSchema.getOneOf()) {

    Unexpected error: Cannot invoke "java.util.List.iterator()" because the return value of "io.swagger.v3.oas.models.media.ComposedSchema.getOneOf()" is null

    Iterator here has ZERO null-protection. It's funny that issue haven't been fixed for such a long time.

    I believe that null check and replacement with an empty list should do the trick, since after this diff will be emptyList vs nonEmptyList

  2. DrSatyr commented on Feb 23, 2026

    @DrSatyr
    Collaborator

    Thanks for reporting this.

    I think we should scope #381 to the runtime crash only (NPE on oneOf -> anyOf), and handle anyOf semantics separately.

    The anyOf/allOf behavior has already been discussed and tracked:

    For this issue, the proposed fix is specifically to prevent the NPE in ComposedSchemaDiffResult#getMapping when getOneOf() is null (e.g., right side is anyOf).
    That resolves the crash without changing current anyOf merge semantics.

  3. self-assigned this
    on Feb 23, 2026
  4. added a commit that references this issue on Feb 23, 2026
    59f07c3
  5. DrSatyr commented on Feb 23, 2026

    @DrSatyr
    Collaborator

    @bors2908 please review #892

  6. bors2908 commented on Feb 23, 2026

    @bors2908
  7. added a commit that references this issue on Mar 17, 2026
    60e6a9f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions