Skip to content

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

@DeagleGross

Description

@DeagleGross

Description

I've tried union as return type in aspnetcore

public union NullableCaseUnion(int?, string);

app.MapGet("/null",   () => new NullableCaseUnion((int?)null));

and got the following serialization error (full stacktrace below):

System.Text.Json.JsonException : The JSON value could not be converted to System.Int32. Path: $.

I think JsonUnionConverter<TUnion>.OnTryWrite misses a check for caseValue being null in case of valueType. Read side of the converter works well, since it short-curcuits the return checking the tokenType:

if (reader.TokenType is JsonTokenType.Null) {
    Type? nullableCaseType = typeInfo.UnionNullableCaseType;
    value = constructor(nullableCaseType, null);
    return true;
}

Reproduction Steps

string json = await Serializer.SerializeWrapper<ValueTypeNullablePairUnion>(new ValueTypeNullablePairUnion((int?)null));
            ValueTypeNullablePairUnion roundTripped = await Serializer.DeserializeWrapper<ValueTypeNullablePairUnion>(json);
            Assert.Null(roundTripped.Value);

Expected behavior

Serialization rountrip on union union ValueTypeNullablePairUnion(int, int?) works without exception

Actual behavior

throws System.Text.Json.JsonException : The JSON value could not be converted to System.Int32. Path: $.

Serialization error stacktrace
System.Text.Json.JsonException : The JSON value could not be converted to System.Int32. Path: $.

   at System.Text.Json.ThrowHelper.ThrowJsonException_DeserializeUnableToConvertValue(Type propertyType)
        ThrowHelper.Serialization.cs:line 52
   at System.Text.Json.JsonSerializer.UnboxOnWrite[T](Object value)
        JsonSerializer.Helpers.cs:line 139
   at System.Text.Json.Serialization.JsonConverter`1.TryWriteAsObject(
            Utf8JsonWriter writer, Object value, JsonSerializerOptions options, WriteStack& state)
        JsonConverterOfT.cs:line 112
   at System.Text.Json.Serialization.Converters.JsonUnionConverter`1.OnTryWrite(
            Utf8JsonWriter writer, TUnion value, JsonSerializerOptions options, WriteStack& state)
        JsonUnionConverter.cs:line 195                         ← bug origin
   at System.Text.Json.Serialization.JsonConverter`1.TryWrite(
            Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
        JsonConverterOfT.cs:line 425
   at System.Text.Json.Serialization.JsonConverter`1.WriteCore(
            Utf8JsonWriter writer, T& value, JsonSerializerOptions options, WriteStack& state)
        JsonConverterOfT.WriteCore.cs:line 48
   at System.Text.Json.Serialization.Metadata.JsonTypeInfo`1.Serialize(
            Utf8JsonWriter writer, T& rootValue, Object rootValueBoxed)
        JsonTypeInfoOfT.WriteHelpers.cs:line 56
   at System.Text.Json.JsonSerializer.WriteString[TValue](TValue& value, JsonTypeInfo`1 jsonTypeInfo)
        JsonSerializer.Write.String.cs:line 154
   at System.Text.Json.JsonSerializer.Serialize[TValue](TValue value, JsonSerializerOptions options)
        JsonSerializer.Write.String.cs:line 33
   at System.Text.Json.Serialization.Tests.JsonSerializerWrapper.StringSerializerWrapper.SerializeWrapper[T](
            T value, JsonSerializerOptions options)
        JsonSerializerWrapper.Reflection.cs:line 119
   at System.Text.Json.Serialization.Tests.UnionTests
            .<UnionWithValueTypeNullableCase_SerializesNullAsJsonNull>d__53.MoveNext()
        UnionTests.cs:line 571
   --- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)

Regression?

No response

Known Workarounds

No response

Configuration

No response

Other information

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions