Skip to content

openapi: a nullable type array overstates nullability when the enum excludes null #288

Description

@OmarAlJarrah

Summary

A schema whose type array admits null but whose enum does not list null still
reads as nullable at every reference. The two keywords conjoin, so the enum is the
stricter of the pair and null is not a valid instance — but schemaAdmitsNull
reads only the type array, and the reference gets Nullable: true.

components:
  schemas:
    S:
      type: object
      properties:
        p: {type: [string, "null"], enum: [red, green]}

Compiles to Enum{red, green} — correct — behind a property reference with
nullable: true, which admits a value the document forbids.

Contrast

The same overstatement does not happen through the oneOf spelling:
{enum: [open, closed], oneOf: [{type: string}, {type: "null"}]} correctly reads
as non-nullable, because schemaAdmitsNull reaches that path through
oneOfAnyOfHasNull(s) && !hasUnionSiblings(s) and declaresShape counts a
non-empty enum as a union sibling. Only the schemaHasNull path — the type
array and 3.0 nullable: true — skips that check.

So the inconsistency is between two spellings of the same thing: an enum
suppresses the oneOf null but not the type-array null.

Scope

Pre-existing, and independent of #44's normalization: that change only alters
behavior when the member list does contain null, and here it does not. It is
adjacent because both concern whether schemaAdmitsNull is an accurate predicate
for "this enum admits null" — it is exact in the direction #44 relies on (a null
member is dropped exactly where a reference puts it back) and overstates in this
one.

Fixing it means making the schemaHasNull path enum-aware the way the oneOf
path already is, which touches every site that computes nullability — the same
blast radius #265 describes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions