Skip to content

NullReferenceException on boolean schema in components/schemas #2838

@pawlos

Description

@pawlos

Describe the bug
OpenApiDocument.Load throws NullReferenceException from Microsoft.OpenApi.OpenApiWorkspace.RegisterComponents when an OpenAPI 3.1 document contains a components/schemas entry whose value is a JSON boolean - e.g. "X": true.

The input is spec-valid. OpenAPI 3.1 §4.8.24 defines its Schema Object as "a superset of the JSON Schema Specification Draft 2020-12", and JSON Schema 2020-12 §4.3.2 "Boolean JSON Schemas" permits a schema to be the literal true (always validates) or false (never validates). The parser should either materialize a proper schema value for these entries or surface a structured diagnostic - not throw NullReferenceException.

Affected:

  • Microsoft.OpenApi 3.5.2 (latest release)
  • main at 78e17ca (2026-04-23) - still reproduces

OpenApi File To Reproduce
55-byte JSON file:

{"openapi":"3.1.0","components":{"schemas":{"X":true}}}

info is a required field per the OpenAPI spec, but the deserializer still reaches RegisterComponents without it, so it can be omitted from the minimal repro. Adding "info":{"title":"x","version":"1"} does not change the behavior.

Expected behavior
The parser should not throw NullReferenceException on a spec-valid OpenAPI 3.1 document. Either accepting the boolean schema or surfacing a structured diagnostic would be fine - how boolean schemas are represented in the object model is a design decision for the maintainers.

Screenshots/Code Snippets
Repro:

using Microsoft.OpenApi;
using Microsoft.OpenApi.Reader;

var bytes = "{\"openapi\":\"3.1.0\",\"components\":{\"schemas\":{\"X\":true}}}"u8.ToArray();
using var ms = new MemoryStream(bytes);
OpenApiDocument.Load(ms, format: null, new OpenApiReaderSettings());
// -> System.NullReferenceException at OpenApiWorkspace.RegisterComponents

Stack trace:

System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.OpenApi.OpenApiWorkspace.RegisterComponents(OpenApiDocument document)
       in src/Microsoft.OpenApi/Services/OpenApiWorkspace.cs:line 96
   at Microsoft.OpenApi.Reader.V31.OpenApiV31Deserializer.LoadOpenApi(RootNode, Uri)
       in src/Microsoft.OpenApi/Reader/V31/OpenApiDocumentDeserializer.cs:line 61
   at Microsoft.OpenApi.Reader.V31.OpenApiV31VersionService.LoadDocument(RootNode, Uri)
       in src/Microsoft.OpenApi/Reader/V31/OpenApiV31VersionService.cs:line 59
   at Microsoft.OpenApi.Reader.ParsingContext.Parse(JsonNode, Uri)
   at Microsoft.OpenApi.Reader.OpenApiJsonReader.Read(JsonNode, Uri, OpenApiReaderSettings)
   at Microsoft.OpenApi.Reader.OpenApiJsonReader.Read(MemoryStream, Uri, OpenApiReaderSettings)
   at Microsoft.OpenApi.Reader.OpenApiModelFactory.InternalLoad(MemoryStream, string, OpenApiReaderSettings)
   at Microsoft.OpenApi.Reader.OpenApiModelFactory.Load(MemoryStream, string, OpenApiReaderSettings)
   at Microsoft.OpenApi.OpenApiDocument.Load(MemoryStream, string, OpenApiReaderSettings)

When the schema deserializer encounters a bare boolean in place of a schema object, the resulting Components.Schemas dictionary contains an entry with a null value. The document?.Components == null guard at the top of RegisterComponents does not catch this; the per-entry dereference then throws.

The same loop shape exists for every other component map in this method - Parameters, Responses, RequestBodies, Links, Callbacks, Examples, Headers, SecuritySchemes, PathItems - and may be worth a consistency audit for the same null-value pattern.

Additional context

  • Runtime: .NET 10.0 SDK; purely managed code, reproduces on all platforms.
  • Discovery: coverage-guided fuzzing with AFL++ 4.00c + SharpFuzz 2.2.0 against Microsoft.OpenApi 3.5.2. The 55-byte repro above is minimized from a larger AFL-produced crash input.

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