Skip to content

Fix JsonException message property type info in class parameterized constructor#126575

Open
XeronOwO wants to merge 1 commit intodotnet:mainfrom
XeronOwO:fix_json_exception_type
Open

Fix JsonException message property type info in class parameterized constructor#126575
XeronOwO wants to merge 1 commit intodotnet:mainfrom
XeronOwO:fix_json_exception_type

Conversation

@XeronOwO
Copy link
Copy Markdown

@XeronOwO XeronOwO commented Apr 6, 2026

This pull request fixes an incorrect type hint in the thrown JsonException when deserialization fails for classes with parameterized constructors.

Reproduction

using System.Text.Json;

Test<NormalClass>();
Test<ParameterizedNormalClass>();
Test<RecordClass>();
Test<NormalStruct>();
Test<ParameterizedNormalStruct>();
Test<RecordStruct>();

static void Test<T>()
{
	try
	{
		JsonSerializer.Deserialize<T>("{\"Text\":{}}"); // create json convert exception manually
	}
	catch (Exception e)
	{
		Console.WriteLine(e.Message);
	}
}

class NormalClass
{
	public string Text { get; set; } = null!;
}

class ParameterizedNormalClass(string text)
{
	public string Text { get; set; } = text;
}

record RecordClass(string Text);

struct NormalStruct()
{
	public string Text { get; set; } = null!;
}

struct ParameterizedNormalStruct(string text)
{
	public string Text { get; set; } = text;
}

record struct RecordStruct(string Text);

Expected Output

The JSON value could not be converted to System.String. Path: $.Text | LineNumber: 0 | BytePositionInLine: 9.
The JSON value could not be converted to System.String. Path: $.Text | LineNumber: 0 | BytePositionInLine: 9.
The JSON value could not be converted to System.String. Path: $.Text | LineNumber: 0 | BytePositionInLine: 9.
The JSON value could not be converted to System.String. Path: $.Text | LineNumber: 0 | BytePositionInLine: 9.
The JSON value could not be converted to System.String. Path: $.Text | LineNumber: 0 | BytePositionInLine: 9.
The JSON value could not be converted to System.String. Path: $.Text | LineNumber: 0 | BytePositionInLine: 9.

Actual Output

The JSON value could not be converted to System.String. Path: $.Text | LineNumber: 0 | BytePositionInLine: 9.
The JSON value could not be converted to ParameterizedNormalClass. Path: $.Text | LineNumber: 0 | BytePositionInLine: 9.
The JSON value could not be converted to RecordClass. Path: $.Text | LineNumber: 0 | BytePositionInLine: 9.
The JSON value could not be converted to System.String. Path: $.Text | LineNumber: 0 | BytePositionInLine: 9.
The JSON value could not be converted to System.String. Path: $.Text | LineNumber: 0 | BytePositionInLine: 9.
The JSON value could not be converted to System.String. Path: $.Text | LineNumber: 0 | BytePositionInLine: 9.

Root Cause

For classes with parameterized constructors, state.Current.CtorArgumentState.JsonParameterInfo was used instead of state.Current.JsonPropertyInfo.
(All structs, including parameterized structs and record structs, work correctly without this issue.)

jsonParameterInfo = jsonPropertyInfo.AssociatedParameter;
if (jsonParameterInfo != null)
{
state.Current.JsonPropertyInfo = null;
state.Current.CtorArgumentState!.JsonParameterInfo = jsonParameterInfo;
state.Current.NumberHandling = jsonParameterInfo.NumberHandling;

As a result, the exception message fell back to state.Current.JsonTypeInfo.Type for affected classes.

// Use a default message.
Type propertyType = state.Current.JsonPropertyInfo?.PropertyType ?? state.Current.JsonTypeInfo.Type;
message = SR.Format(SR.DeserializeUnableToConvertValue, propertyType);

Fix

Added logic to retrieve type information from state.Current.CtorArgumentState.JsonParameterInfo.ParameterType, ensuring correct type resolution for classes with parameterized constructors.

@dotnet-policy-service dotnet-policy-service bot added the community-contribution Indicates that the PR has been added by a community member label Apr 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-System.Text.Json community-contribution Indicates that the PR has been added by a community member

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant