diff --git a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs index f23a02a036e282..afccfa57946fe1 100644 --- a/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs +++ b/src/libraries/System.Text.Json/src/System/Text/Json/ThrowHelper.Serialization.cs @@ -540,7 +540,9 @@ public static void AddJsonExceptionInformation(scoped ref ReadStack state, in Ut if (string.IsNullOrEmpty(message)) { // Use a default message. - Type propertyType = state.Current.JsonPropertyInfo?.PropertyType ?? state.Current.JsonTypeInfo.Type; + Type propertyType = state.Current.JsonPropertyInfo?.PropertyType ?? + state.Current.CtorArgumentState?.JsonParameterInfo?.ParameterType ?? + state.Current.JsonTypeInfo.Type; message = SR.Format(SR.DeserializeUnableToConvertValue, propertyType); ex.AppendPathInformation = true; } diff --git a/src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.Exceptions.cs b/src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.Exceptions.cs index 9f2db72f2d9987..c80bf5f3a101f4 100644 --- a/src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.Exceptions.cs +++ b/src/libraries/System.Text.Json/tests/Common/ConstructorTests/ConstructorTests.Exceptions.cs @@ -350,5 +350,31 @@ public ClassWithInvalidDictionary(Dictionary unsupportedDictiona UnsupportedDictionary = unsupportedDictionary; } } + + [Fact] + public async Task ParameterizedConstructor_ExceptionMessage_ReportsPropertyType() + { + // Regression test: classes with parameterized constructors should report the + // property type (System.String), not the declaring class type, in the JsonException message. + // https://github.com/dotnet/runtime/pull/126575 + JsonException e; + + e = await Assert.ThrowsAsync(() => + Serializer.DeserializeWrapper("""{"Text":{}}""")); + Assert.Contains("System.String", e.Message); + Assert.DoesNotContain(nameof(ParameterizedClass_WithStringProperty), e.Message); + + e = await Assert.ThrowsAsync(() => + Serializer.DeserializeWrapper("""{"Text":{}}""")); + Assert.Contains("System.String", e.Message); + Assert.DoesNotContain(nameof(ParameterizedRecord_WithStringProperty), e.Message); + } + + public class ParameterizedClass_WithStringProperty(string text) + { + public string Text { get; set; } = text; + } + + public record ParameterizedRecord_WithStringProperty(string Text); } } diff --git a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/ConstructorTests.cs b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/ConstructorTests.cs index 8aae01fb6ddf30..1f1726d2f5fe43 100644 --- a/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/ConstructorTests.cs +++ b/src/libraries/System.Text.Json/tests/System.Text.Json.SourceGeneration.Tests/Serialization/ConstructorTests.cs @@ -177,6 +177,8 @@ protected ConstructorTests_Metadata(JsonSerializerWrapper stringWrapper) [JsonSerializable(typeof(TypeWith_RefReadonlyParameter_Primitive))] [JsonSerializable(typeof(TypeWith_RefReadonlyParameter_Struct))] [JsonSerializable(typeof(TypeWith_RefReadonlyParameter_ReferenceType))] + [JsonSerializable(typeof(ParameterizedClass_WithStringProperty))] + [JsonSerializable(typeof(ParameterizedRecord_WithStringProperty))] internal sealed partial class ConstructorTestsContext_Metadata : JsonSerializerContext { } @@ -349,6 +351,8 @@ public ConstructorTests_Default(JsonSerializerWrapper jsonSerializer) : base(jso [JsonSerializable(typeof(TypeWith_RefReadonlyParameter_Primitive))] [JsonSerializable(typeof(TypeWith_RefReadonlyParameter_Struct))] [JsonSerializable(typeof(TypeWith_RefReadonlyParameter_ReferenceType))] + [JsonSerializable(typeof(ParameterizedClass_WithStringProperty))] + [JsonSerializable(typeof(ParameterizedRecord_WithStringProperty))] internal sealed partial class ConstructorTestsContext_Default : JsonSerializerContext { }