Skip to content

[BUG][core] Normalize OAS 3.1 type: null map value (additionalProperties) under NORMALIZE_31SPEC - #23967

Merged
wing328 merged 1 commit into
OpenAPITools:masterfrom
seonwooj0810:fix/issue-23945-normalize31spec-null-map-value
Jul 14, 2026
Merged

[BUG][core] Normalize OAS 3.1 type: null map value (additionalProperties) under NORMALIZE_31SPEC#23967
wing328 merged 1 commit into
OpenAPITools:masterfrom
seonwooj0810:fix/issue-23945-normalize31spec-null-map-value

Conversation

@seonwooj0810

@seonwooj0810 seonwooj0810 commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

Fixes #23945

Problem

With --openapi-normalizer NORMALIZE_31SPEC=true, a nullable map whose additionalProperties value schema still contains JSON Schema null was not normalized to a usable OAS 3.0 value type. Generators emitted a fictional Null / ModelNull value type that fails to compile, e.g. Map<String, ModelNull> (Java) with no ModelNull model generated, Dictionary<string, Null> (csharp, CS0246), etc.

Two value-schema shapes from the report:

stringMap:
  type: [object, "null"]
  additionalProperties:
    type: "null"
errorsByKey:
  type: [object, "null"]
  additionalProperties:
    type: [array, "null"]
    items: { ... }

Root cause

In OpenAPINormalizer#normalizeSchema, the map branch recurses into additionalProperties but:

  1. A pure type: "null" value schema is short-circuited by ModelUtils.isNullTypeSchema(...) at the top of normalizeSchema and returned unchanged, so it keeps its OAS 3.1 null type.
  2. A type: [array, "null"] value schema is converted by processNormalize31Spec into a new ArraySchema, but the map branch discarded the return value (normalizeSchema(...) was called without reassigning additionalProperties), leaving the value half-converted.

This is the remaining gap after #22056 (which covered additionalProperties: false on closed objects, not nullable map values).

Fix

In the map branch, when NORMALIZE_31SPEC is enabled:

  • rewrite a pure-null additionalProperties value to an any-type nullable schema, so the map value generates as a normal (nullable) object; and
  • capture the normalized value schema for the other cases (so the [array, "null"] rewrite is not lost).

The change is fully gated behind NORMALIZE_31SPEC; behavior is unchanged when the rule is off. No committed sample config uses NORMALIZE_31SPEC, so no generated samples change.

Test evidence

Added OpenAPINormalizerTest#testOpenAPINormalizer31SpecNullMapAdditionalProperties (spec src/test/resources/3_1/issue_23945.yaml) asserting the stringMap value loses its null type (becomes any-type nullable) and the errorsByKey value becomes a nullable array.

mvn -pl modules/openapi-generator test -Dtest=OpenAPINormalizerTest
Tests run: 61, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS

Verification done: (1) confirmed no in-flight PR (gh pr list search for NORMALIZE_31SPEC/23945 returned none); (2) no self-claim — issue has 0 comments; (3) code-only change to .java + test; (4) reproduced the bug on master with a failing assertion before the fix (stringMap value stayed types=[null], errorsByKey value stayed type=null/types=[array]); (5) full OpenAPINormalizerTest (61 tests) green.

🤖 Generated with Claude Code


Summary by cubic

Fixes normalization of OAS 3.1 nullable map value schemas under NORMALIZE_31SPEC so generators stop emitting fictional Null/ModelNull types and maps compile.

  • Bug Fixes
    • In OpenAPINormalizer#normalizeSchema, if additionalProperties is type: "null", rewrite to an any-type nullable schema.
    • Reassign the normalized value schema (e.g., type: [array, "null"] → nullable array) so the rewrite isn’t lost.
    • Changes gated behind NORMALIZE_31SPEC; default behavior unchanged.
    • Added OpenAPINormalizerTest#testOpenAPINormalizer31SpecNullMapAdditionalProperties and 3_1/issue_23945.yaml to cover both shapes.

Written for commit 6b8ab05. Summary will update on new commits.

Review in cubic

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 3 files

Re-trigger cubic

@wing328

wing328 commented Jun 8, 2026

Copy link
Copy Markdown
Member
  additionalProperties:
    type: "null"

should the normalizer simply remove this ?

@seonwooj0810

Copy link
Copy Markdown
Contributor Author

Yes, that is essentially the intent for the pure additionalProperties: { type: "null" } case, with one nuance: the patch does not remove additionalProperties outright. It replaces the OAS 3.1 null value schema with an any-type nullable schema.

I chose that because there is no OAS 3.0 null type to preserve, and keeping it as null makes generators produce a fictional Null / ModelNull map value type that does not compile. Using a nullable any-type value preserves the fact that the schema is still a map whose values are allowed to be nullable, while avoiding the generated Null model.

For the mixed type: [array, "null"] case, the PR keeps more structure: it captures the normalized nullable array schema instead of dropping it. So the behavior is:

  • pure null map value: normalize to nullable any-type
  • array | null map value: normalize to nullable array with items preserved

If you would prefer the pure-null case to remove additionalProperties instead, I can switch it, but I think the nullable any-type fallback is a little less lossy.

@wing328

wing328 commented Jun 30, 2026

Copy link
Copy Markdown
Member

thanks for the explanation

please resolve the merge conflicts when you've time.

A nullable map whose `additionalProperties` value schema is `type: "null"`
(or `type: [array, "null"]`) was not normalized to a usable OAS 3.0 value
type. Generators emitted a fictional `Null` / `ModelNull` value type that
fails to compile (e.g. `Map<String, ModelNull>` with no `ModelNull` model).

A pure `type: "null"` value schema is short-circuited by
`ModelUtils.isNullTypeSchema` before normalization, so it kept its OAS 3.1
null type. A `type: [array, "null"]` value was converted to a new array
schema whose result was then discarded by the map branch.

When NORMALIZE_31SPEC is enabled, rewrite a pure-null map value to an
any-type nullable schema and capture the normalized value schema for the
array case. Behavior is unchanged unless NORMALIZE_31SPEC is enabled.

Fixes OpenAPITools#23945

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: seonwoo_jung <79202163+seonwooj0810@users.noreply.github.com>
@seonwooj0810
seonwooj0810 force-pushed the fix/issue-23945-normalize31spec-null-map-value branch from ed90132 to 6b8ab05 Compare July 1, 2026 16:47
@seonwooj0810

Copy link
Copy Markdown
Contributor Author

@wing328 Thanks! I've rebased onto the latest master and resolved the merge conflicts. The only conflict was in OpenAPINormalizerTest.java where both branches appended new test methods at the end of the class — I kept both sets (the testIssue24139... tests from master and my testOpenAPINormalizer31SpecNullMapAdditionalProperties). All three pass locally. Ready for another look whenever you have time.

@seonwooj0810

Copy link
Copy Markdown
Contributor Author

Friendly ping, @wing328. Following up on the rebase you requested — the branch is still MERGEABLE / clean against master with no conflicts, and all CircleCI nodes are green. It should be ready to merge whenever you have a moment. Thanks!

@wing328

wing328 commented Jul 14, 2026

Copy link
Copy Markdown
Member

did a test locally with java client generator and the result looks good:

-  private Map<String, ModelNull> stringMap = new HashMap<>();
+  private Map<String, Object> stringMap = new HashMap<>();

@wing328
wing328 merged commit 82f8611 into OpenAPITools:master Jul 14, 2026
14 checks passed
@wing328 wing328 added Issue: Bug OpenAPI Normalizer Normalize the spec for easier processing labels Jul 14, 2026
@wing328 wing328 added this to the 7.24.0 milestone Jul 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Issue: Bug OpenAPI Normalizer Normalize the spec for easier processing

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG][MULTIPLE][OAS 3.1] Nullable map with additionalProperties type null breaks codegen (Null/ModelNull) with NORMALIZE_31SPEC (7.17+)

2 participants