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.
Summary
A schema whose type array admits null but whose
enumdoes not listnullstillreads as nullable at every reference. The two keywords conjoin, so the enum is the
stricter of the pair and
nullis not a valid instance — butschemaAdmitsNullreads only the type array, and the reference gets
Nullable: true.Compiles to
Enum{red, green}— correct — behind a property reference withnullable: true, which admits a value the document forbids.Contrast
The same overstatement does not happen through the
oneOfspelling:{enum: [open, closed], oneOf: [{type: string}, {type: "null"}]}correctly readsas non-nullable, because
schemaAdmitsNullreaches that path throughoneOfAnyOfHasNull(s) && !hasUnionSiblings(s)anddeclaresShapecounts anon-empty
enumas a union sibling. Only theschemaHasNullpath — the typearray and 3.0
nullable: true— skips that check.So the inconsistency is between two spellings of the same thing: an enum
suppresses the
oneOfnull 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 isadjacent because both concern whether
schemaAdmitsNullis an accurate predicatefor "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
schemaHasNullpath enum-aware the way theoneOfpath already is, which touches every site that computes nullability — the same
blast radius #265 describes.