Skip to content

Fix JsonSerializer throws when serializing null value in a value-type nullable union case#128689

Open
DeagleGross wants to merge 1 commit into
dotnet:mainfrom
DeagleGross:dmkorolev/unions/fix-deconstructor-nullable
Open

Fix JsonSerializer throws when serializing null value in a value-type nullable union case#128689
DeagleGross wants to merge 1 commit into
dotnet:mainfrom
DeagleGross:dmkorolev/unions/fix-deconstructor-nullable

Conversation

@DeagleGross
Copy link
Copy Markdown
Member

I've added roundtrip test on existing union ValueTypeNullablePairUnion(int, int?); to verify that nullable case value works well for valueType. There are existing tests checking the same for string?.

Fixes #128688

@DeagleGross DeagleGross self-assigned this May 28, 2026
Copilot AI review requested due to automatic review settings May 28, 2026 10:40
@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @dotnet/area-system-text-json
See info in area-owners.md if you want to be subscribed.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Fixes #128688 where serializing a union with a value-type nullable case (e.g., union ValueTypeNullablePairUnion(int, int?)) holding a null value would throw, because the deconstructor returns (typeof(int), null) and dispatching null to the int converter fails in UnboxOnWrite<T>. The write path now short-circuits to JSON null when the case type is a value type and the case value is null, mirroring the existing null-handling on the read path.

Changes:

  • In JsonUnionConverter<TUnion>.OnTryWrite, write JSON null directly when the deconstructor returns a value-type case with a null value.
  • Add UnionWithValueTypeNullableCase_SerializesNullAsJsonNull and UnionWithValueTypeNullableCase_RoundTripsNullValue tests over the existing ValueTypeNullablePairUnion, exercised via both reflection and source-generation contexts.
Show a summary per file
File Description
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Union/JsonUnionConverter.cs Adds the null-value/value-type guard before dispatching to the case converter.
src/libraries/System.Text.Json/tests/Common/UnionTests.cs Adds serialization and roundtrip tests for value-type nullable union cases.

Copilot's findings

  • Files reviewed: 2/2 changed files
  • Comments generated: 1

// If the deconstructor reports a value-type case holding null,
// write JSON null directly rather than dispatching to the value-type's converter
// (which cannot unbox null).
if (caseValue is null && caseType.IsValueType) {
// If the deconstructor reports a value-type case holding null,
// write JSON null directly rather than dispatching to the value-type's converter
// (which cannot unbox null).
if (caseValue is null && caseType.IsValueType) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The failure suggests to me that caseTypeInfo.Converter is JsonConverter<int> rather than JsonConverter<int?> which should handle null values without issue. So I suspect this might be an issue with either the union metadata or the deconstructor returning an incorrect case type.

Are you hitting this using the source generator, reflection, or both?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I got it in both source gen and reflection. Not sure why it hits this specific converter though. I can take a look later

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

JsonSerializer throws when serializing null value in a value-type nullable union case

3 participants