Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 23, 2026

OpenAPI 3.0 properties marked nullable: true were generating non-nullable F# types, causing System.Text.Json.JsonException at runtime when deserializing null values.

Changes

  • Added isSchemaNullable helper to detect JsonSchemaType.Null flag (how Microsoft.OpenApi v2.4.1 represents OpenAPI 3.0's nullable: true)
  • Updated property type logic to wrap nullable properties as Option<T> regardless of required status
  • Fixed constructor parameters to apply same nullable-aware logic for consistency

Implementation

The fix treats properties as optional when either not required OR nullable:

let isSchemaNullable (schema: IOpenApiSchema) =
    not (isNull schema) && schema.Type.HasValue && schema.Type.Value.HasFlag(JsonSchemaType.Null)

let isRequired = schemaObjRequired.Contains propName && not isNullable

This correctly handles all OpenAPI combinations:

  • required: true, nullable: trueOption<T> (present but can be null)
  • required: true, nullable: falseT (present and non-null)
  • required: false, nullable: *Option<T> (can be absent)

Test

Added schema nullable-date.yaml and test verifying nullable date fields generate Option<DateTimeOffset> types.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • petstore.swagger.io
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/10.0.102/FSharp/fsc.dll @/tmp/MSBuildTempfAICPP/tmp8a486eb65866450a9fd32f652001aa9b.rsp (dns block)
    • Triggering command: /usr/share/dotnet/dotnet /usr/share/dotnet/dotnet /usr/share/dotnet/sdk/10.0.102/FSharp/fsc.dll @/tmp/MSBuildTempWPH3E8/tmpd9bb636ed2714511bacccb5154efa42e.rsp k/SwaggerProvider/SwaggerProvidesrc/SwaggerProvider.DesignTime/obj/Release/netstandard2.0/.NETStandard,Version=v2.0.AssemblyAttributes.fs Shar�� 8f39f2440a5a1cf887f1d8747e7.rsp (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

This section details on the original issue you should resolve

<issue_title>Cannot deserialise null date</issue_title>
<issue_description>When using the OpenApiProvider with the Immich API, it cannot deserialise PersonResponseDtos if their birthdate has not been set.

Reproduction Steps

  1. Get API key for the immich api demo from https://api.immich.app/endpoints/api-keys/getApiKeys
  2. Run the below script
#r "nuget: SwaggerProvider, 3.0.0-beta04"
open SwaggerProvider
open System
open System.Net.Http

let  [<Literal>] private Schema = "https://raw.githubusercontent.com/immich-app/immich/refs/heads/main/open-api/immich-openapi-specs.json"
type Api = OpenApiClientProvider<Schema>

let httpClient = new HttpClient()
httpClient.BaseAddress <- URI "https://demo.immich.app/api/"
httpClient.DefaultRequestHeaders.Add ("x-api-key", "{Key from step 1}")
let apiClient = Api.Client httpClient

apiClient.GetAllPeople()
|> Async.AwaitTask
|> Async.RunSynchronously

Result

The following exception is raised

Error: System.AggregateException: One or more errors occurred. (The JSON value could not be converted to System.DateTimeOffset. Path: $.people[0].birthDate | LineNumber: 0 | BytePositionInLine: 86.)
---> System.Text.Json.JsonException: The JSON value could not be converted to System.DateTimeOffset. Path: $.people[0].birthDate | LineNumber: 0 | BytePositionInLine: 86.
---> System.InvalidOperationException: Cannot get the value of a token type 'Null' as a string.Error: System.AggregateException: One or more errors occurred. (The JSON value could not be converted to System.DateTimeOffset. Path: $.people[0].birthDate | LineNumber: 0 | BytePositionInLine: 86.)
---> System.Text.Json.JsonException: The JSON value could not be converted to System.DateTimeOffset. Path: $.people[0].birthDate | LineNumber: 0 | BytePositionInLine: 86.
---> System.InvalidOperationException: Cannot get the value of a token type 'Null' as a string.

From the api explorer you can see that a person with no registered birthdate takes the following form:

        {
            "id": "04a38328-4202-44ef-9f2b-ee85b1cd1a48",
            "name": "Test",
            "birthDate": null,
            "thumbnailPath": "/data/thumbs/6bbe2767-7851-461a-aa2d-afbd3460aa85/04/a3/04a38328-4202-44ef-9f2b-ee85b1cd1a48.jpeg",
            "isHidden": false,
            "isFavorite": false,
            "updatedAt": "2026-01-23T11:52:27.606Z"
        }

And their OpenAPI spec does correctly declare birthDate as nullable:

     "PersonResponseDto": {
        "properties": {
          "birthDate": {
            "format": "date",
            "nullable": true,
            "type": "string"
          },
```</issue_description>

<agent_instructions>ensure that nullable is handled correctly</agent_instructions>

## Comments on the Issue (you are @copilot in this section)

<comments>
</comments>

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Copilot AI and others added 5 commits January 23, 2026 13:15
Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com>
Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com>
Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com>
…lity

Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com>
Co-authored-by: sergey-tihon <1197905+sergey-tihon@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix null date deserialization for PersonResponseDto Fix nullable property deserialization in OpenAPI v3 provider Jan 23, 2026
Copilot AI requested a review from sergey-tihon January 23, 2026 13:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cannot deserialise null date

2 participants