Skip to content

Fix null return condition in NullableConverter<T>.OnTryRead#129220

Open
prozolic wants to merge 2 commits into
dotnet:mainfrom
prozolic:nullableconverter
Open

Fix null return condition in NullableConverter<T>.OnTryRead#129220
prozolic wants to merge 2 commits into
dotnet:mainfrom
prozolic:nullableconverter

Conversation

@prozolic

Copy link
Copy Markdown
Contributor

This PR change the early return guard in NullableConverter<T>.OnTryRead from !state.IsContinuation to state.Current.ObjectState == StackFrameObjectState.None.

On continuation re-entry, ReadStack.Push resets _continuationCount to 0 when _continuationCount == _count (i.e., the deepest frame is reached), causing IsContinuation to return false before OnTryRead is entered.
ObjectState is saved in the frame and shows if the element converter has started processing the current value. It is None only on the very first entry, so replacing !IsContinuation with ObjectState == None correctly skips the early-return regardless of _continuationCount state.

Closes #125237

Change the early return guard in NullableConverter<T>.OnTryRead from
!state.IsContinuation to state.Current.ObjectState == StackFrameObjectState.None.

On continuation re-entry, ReadStack.Push resets _continuationCount to 0
when _continuationCount == _count (i.e., the deepest frame is reached),
causing IsContinuation to return false before OnTryRead is entered.

ObjectState is saved in the frame and shows if the element converter
has started processing the current value. It is None only
on the very first entry, so replacing !IsContinuation with
ObjectState == None correctly skips the early-return regardless of
_continuationCount state.
Copilot AI review requested due to automatic review settings June 10, 2026 07:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds a regression test for stream-based deserialization around nullable structs and adjusts nullable reading logic to handle null tokens in continuation scenarios.

Changes:

  • Add a new stream-based regression test targeting a buffer-boundary edge case.
  • Update NullableConverter<T>.OnTryRead to treat null tokens as null values based on stack object state rather than IsContinuation.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
src/libraries/System.Text.Json/tests/System.Text.Json.Tests/Serialization/NullableTests.cs Adds a new regression test and helper types for stream/buffer boundary handling.
src/libraries/System.Text.Json/src/System/Text/Json/Serialization/Converters/Value/NullableConverter.cs Adjusts nullable null token handling during incremental/continuation reads.

Comment on lines 30 to 35
internal override bool OnTryRead(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options, scoped ref ReadStack state, out T? value)
{
if (!state.IsContinuation && reader.TokenType == JsonTokenType.Null)
if (state.Current.ObjectState == StackFrameObjectState.None && reader.TokenType == JsonTokenType.Null)
{
value = null;
return true;
@prozolic prozolic marked this pull request as ready for review June 10, 2026 07:12
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.

System.Text.Json deserializes struct properties as null when reading from a stream - bug introduced in v9+

2 participants