From 275dd73214fbc40073a126956fc35311f46b369f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:46:52 +0000 Subject: [PATCH 1/6] Initial plan From c0691a6d4bb7dda4bdb4bc84bf469feadce59ea4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:53:47 +0000 Subject: [PATCH 2/6] Add breaking change documentation for System.Text.Json metadata property validation Co-authored-by: gewarren <24882762+gewarren@users.noreply.github.com> --- docs/core/compatibility/10.0.md | 1 + .../json-validates-metadata-property-names.md | 102 ++++++++++++++++++ docs/core/compatibility/toc.yml | 2 + 3 files changed, 105 insertions(+) create mode 100644 docs/core/compatibility/serialization/10/json-validates-metadata-property-names.md diff --git a/docs/core/compatibility/10.0.md b/docs/core/compatibility/10.0.md index 4a91f0a4924ed..2dfc06a47fadf 100644 --- a/docs/core/compatibility/10.0.md +++ b/docs/core/compatibility/10.0.md @@ -141,6 +141,7 @@ If you're migrating an app to .NET 10, the breaking changes listed here might af | Title | Type of change | |-------|-------------------| +| [System.Text.Json validates property names conflicting with metadata properties](serialization/10/json-validates-metadata-property-names.md) | Behavioral change | | [XmlSerializer no longer ignores properties marked with ObsoleteAttribute](serialization/10/xmlserializer-obsolete-properties.md) | Behavioral change | ## Windows Forms diff --git a/docs/core/compatibility/serialization/10/json-validates-metadata-property-names.md b/docs/core/compatibility/serialization/10/json-validates-metadata-property-names.md new file mode 100644 index 0000000000000..7beda9747ed18 --- /dev/null +++ b/docs/core/compatibility/serialization/10/json-validates-metadata-property-names.md @@ -0,0 +1,102 @@ +--- +title: "Breaking change: System.Text.Json validates property names conflicting with metadata properties" +description: "Learn about the breaking change in .NET 10 where System.Text.Json validates that user-defined property names don't conflict with reserved metadata property names." +ms.date: 11/13/2025 +ai-usage: ai-assisted +--- +# System.Text.Json validates property names conflicting with metadata properties + +Starting in .NET 10, validates that user-defined property names don't conflict with reserved metadata property names used in specific serialization contexts. Under certain contexts, such as polymorphism and reference preservation, System.Text.Json reserves specific property names (`$type`, `$id`, `$ref`, and others) for emitting metadata. Previously, the serializer didn't perform validation on whether these property names conflicted with user-defined contracts, which could result in duplicate properties and produce JSON that is ambiguous or fails to round-trip. Starting with .NET 10, System.Text.Json enables validation to prevent such configurations and provides early warning to users. + +## Version introduced + +.NET 10 + +## Previous behavior + +Previously, the following code would produce an invalid JSON object with duplicate `Type` properties and fail to deserialize with a deserialization exception: + +```csharp +using System.Text.Json; +using System.Text.Json.Serialization; + +string json = JsonSerializer.Serialize(new Dog()); +Console.WriteLine(json); // {"Type":"dog","Type":"Dog"} +JsonSerializer.Deserialize(json); // JsonException: Deserialized object contains a duplicate 'Type' metadata property. + +[JsonPolymorphic(TypeDiscriminatorPropertyName = "Type")] +[JsonDerivedType(typeof(Dog), "dog")] +public abstract class Animal +{ + public abstract string Type { get; } +} + +public class Dog : Animal +{ + public override string Type => "Dog"; +} +``` + +The serializer would emit duplicate properties in the JSON output and fail during deserialization. + +## New behavior + +Starting in .NET 10, any attempt to serialize that same type results in an early validation error: + +``` +InvalidOperationException: The type 'Dog' contains property 'Type' that conflicts with an existing metadata property name. Consider either renaming it or ignoring it with JsonIgnoreAttribute +``` + +This validation error occurs when the serializer is first created or when serialization is first attempted, providing early detection of invalid serialization contracts. + +## Type of breaking change + +This change is a [behavioral change](../../categories.md#behavioral-change). + +## Reason for change + +This change provides early prevention of invalid serialization contracts. By validating property names upfront, the serializer prevents scenarios where duplicate properties would be emitted, resulting in invalid JSON that cannot round-trip correctly. This helps developers identify and fix configuration issues during development rather than discovering them at runtime during deserialization. + +## Recommended action + +Users should avoid using property names that conflict with System.Text.Json-specific metadata properties (`$type`, `$id`, `$ref`, and others). If it's absolutely necessary to keep such a property in the class, apply a annotation on the conflicting property: + +```csharp +[JsonPolymorphic(TypeDiscriminatorPropertyName = "Type")] +[JsonDerivedType(typeof(Dog), "dog")] +public abstract class Animal +{ + [JsonIgnore] + public abstract string Type { get; } +} + +public class Dog : Animal +{ + public override string Type => "Dog"; +} +``` + +Alternatively, rename the property to avoid the conflict: + +```csharp +[JsonPolymorphic(TypeDiscriminatorPropertyName = "$type")] +[JsonDerivedType(typeof(Dog), "dog")] +public abstract class Animal +{ + public abstract string AnimalType { get; } +} + +public class Dog : Animal +{ + public override string AnimalType => "Dog"; +} +``` + +## Affected APIs + +- +- +- +- +- +- diff --git a/docs/core/compatibility/toc.yml b/docs/core/compatibility/toc.yml index 78a5d4adf5f58..88af8c7d6571b 100644 --- a/docs/core/compatibility/toc.yml +++ b/docs/core/compatibility/toc.yml @@ -172,6 +172,8 @@ items: href: sdk/10.0/prune-packagereference-privateassets.md - name: Serialization items: + - name: System.Text.Json validates property names conflicting with metadata properties + href: serialization/10/json-validates-metadata-property-names.md - name: XmlSerializer no longer ignores properties marked with ObsoleteAttribute href: serialization/10/xmlserializer-obsolete-properties.md - name: Windows Forms From a54af5d4296d724fff814108187227dc7f5536c7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 13 Nov 2025 16:22:28 +0000 Subject: [PATCH 3/6] Add references to original runtime issue and PR Co-authored-by: jeffhandley <1031940+jeffhandley@users.noreply.github.com> --- .../10/json-validates-metadata-property-names.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/core/compatibility/serialization/10/json-validates-metadata-property-names.md b/docs/core/compatibility/serialization/10/json-validates-metadata-property-names.md index 7beda9747ed18..0821c9473ca90 100644 --- a/docs/core/compatibility/serialization/10/json-validates-metadata-property-names.md +++ b/docs/core/compatibility/serialization/10/json-validates-metadata-property-names.md @@ -57,6 +57,11 @@ This change is a [behavioral change](../../categories.md#behavioral-change). This change provides early prevention of invalid serialization contracts. By validating property names upfront, the serializer prevents scenarios where duplicate properties would be emitted, resulting in invalid JSON that cannot round-trip correctly. This helps developers identify and fix configuration issues during development rather than discovering them at runtime during deserialization. +For more information, see: + +- [[STJ] Disallow property names that conflict with metadata property names (dotnet/runtime#106390)](https://github.com/dotnet/runtime/issues/106390) +- [Disallow types with property names conflicting with metadata (dotnet/runtime#106460)](https://github.com/dotnet/runtime/pull/106460) + ## Recommended action Users should avoid using property names that conflict with System.Text.Json-specific metadata properties (`$type`, `$id`, `$ref`, and others). If it's absolutely necessary to keep such a property in the class, apply a annotation on the conflicting property: From 853dad5b85095e89c3faf1d03336c122be96eb9b Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Thu, 13 Nov 2025 09:55:26 -0800 Subject: [PATCH 4/6] human edits --- docs/core/compatibility/10.0.md | 2 +- .../json-validates-metadata-property-names.md | 107 ------------------ .../10/property-name-validation.md | 69 +++++++++++ docs/core/compatibility/toc.yml | 4 +- 4 files changed, 72 insertions(+), 110 deletions(-) delete mode 100644 docs/core/compatibility/serialization/10/json-validates-metadata-property-names.md create mode 100644 docs/core/compatibility/serialization/10/property-name-validation.md diff --git a/docs/core/compatibility/10.0.md b/docs/core/compatibility/10.0.md index 2dfc06a47fadf..adfbe746acadc 100644 --- a/docs/core/compatibility/10.0.md +++ b/docs/core/compatibility/10.0.md @@ -141,7 +141,7 @@ If you're migrating an app to .NET 10, the breaking changes listed here might af | Title | Type of change | |-------|-------------------| -| [System.Text.Json validates property names conflicting with metadata properties](serialization/10/json-validates-metadata-property-names.md) | Behavioral change | +| [System.Text.Json checks for property name conflicts](serialization/10/property-name-validation.md) | Behavioral change | | [XmlSerializer no longer ignores properties marked with ObsoleteAttribute](serialization/10/xmlserializer-obsolete-properties.md) | Behavioral change | ## Windows Forms diff --git a/docs/core/compatibility/serialization/10/json-validates-metadata-property-names.md b/docs/core/compatibility/serialization/10/json-validates-metadata-property-names.md deleted file mode 100644 index 0821c9473ca90..0000000000000 --- a/docs/core/compatibility/serialization/10/json-validates-metadata-property-names.md +++ /dev/null @@ -1,107 +0,0 @@ ---- -title: "Breaking change: System.Text.Json validates property names conflicting with metadata properties" -description: "Learn about the breaking change in .NET 10 where System.Text.Json validates that user-defined property names don't conflict with reserved metadata property names." -ms.date: 11/13/2025 -ai-usage: ai-assisted ---- -# System.Text.Json validates property names conflicting with metadata properties - -Starting in .NET 10, validates that user-defined property names don't conflict with reserved metadata property names used in specific serialization contexts. Under certain contexts, such as polymorphism and reference preservation, System.Text.Json reserves specific property names (`$type`, `$id`, `$ref`, and others) for emitting metadata. Previously, the serializer didn't perform validation on whether these property names conflicted with user-defined contracts, which could result in duplicate properties and produce JSON that is ambiguous or fails to round-trip. Starting with .NET 10, System.Text.Json enables validation to prevent such configurations and provides early warning to users. - -## Version introduced - -.NET 10 - -## Previous behavior - -Previously, the following code would produce an invalid JSON object with duplicate `Type` properties and fail to deserialize with a deserialization exception: - -```csharp -using System.Text.Json; -using System.Text.Json.Serialization; - -string json = JsonSerializer.Serialize(new Dog()); -Console.WriteLine(json); // {"Type":"dog","Type":"Dog"} -JsonSerializer.Deserialize(json); // JsonException: Deserialized object contains a duplicate 'Type' metadata property. - -[JsonPolymorphic(TypeDiscriminatorPropertyName = "Type")] -[JsonDerivedType(typeof(Dog), "dog")] -public abstract class Animal -{ - public abstract string Type { get; } -} - -public class Dog : Animal -{ - public override string Type => "Dog"; -} -``` - -The serializer would emit duplicate properties in the JSON output and fail during deserialization. - -## New behavior - -Starting in .NET 10, any attempt to serialize that same type results in an early validation error: - -``` -InvalidOperationException: The type 'Dog' contains property 'Type' that conflicts with an existing metadata property name. Consider either renaming it or ignoring it with JsonIgnoreAttribute -``` - -This validation error occurs when the serializer is first created or when serialization is first attempted, providing early detection of invalid serialization contracts. - -## Type of breaking change - -This change is a [behavioral change](../../categories.md#behavioral-change). - -## Reason for change - -This change provides early prevention of invalid serialization contracts. By validating property names upfront, the serializer prevents scenarios where duplicate properties would be emitted, resulting in invalid JSON that cannot round-trip correctly. This helps developers identify and fix configuration issues during development rather than discovering them at runtime during deserialization. - -For more information, see: - -- [[STJ] Disallow property names that conflict with metadata property names (dotnet/runtime#106390)](https://github.com/dotnet/runtime/issues/106390) -- [Disallow types with property names conflicting with metadata (dotnet/runtime#106460)](https://github.com/dotnet/runtime/pull/106460) - -## Recommended action - -Users should avoid using property names that conflict with System.Text.Json-specific metadata properties (`$type`, `$id`, `$ref`, and others). If it's absolutely necessary to keep such a property in the class, apply a annotation on the conflicting property: - -```csharp -[JsonPolymorphic(TypeDiscriminatorPropertyName = "Type")] -[JsonDerivedType(typeof(Dog), "dog")] -public abstract class Animal -{ - [JsonIgnore] - public abstract string Type { get; } -} - -public class Dog : Animal -{ - public override string Type => "Dog"; -} -``` - -Alternatively, rename the property to avoid the conflict: - -```csharp -[JsonPolymorphic(TypeDiscriminatorPropertyName = "$type")] -[JsonDerivedType(typeof(Dog), "dog")] -public abstract class Animal -{ - public abstract string AnimalType { get; } -} - -public class Dog : Animal -{ - public override string AnimalType => "Dog"; -} -``` - -## Affected APIs - -- -- -- -- -- -- diff --git a/docs/core/compatibility/serialization/10/property-name-validation.md b/docs/core/compatibility/serialization/10/property-name-validation.md new file mode 100644 index 0000000000000..876ca60da30fc --- /dev/null +++ b/docs/core/compatibility/serialization/10/property-name-validation.md @@ -0,0 +1,69 @@ +--- +title: "Breaking change: System.Text.Json checks for property name conflicts" +description: "Learn about the breaking change in .NET 10 where System.Text.Json validates that user-defined property names don't conflict with reserved metadata property names." +ms.date: 11/13/2025 +ai-usage: ai-assisted +--- +# System.Text.Json checks for property name conflicts + +Under certain contexts, such as polymorphism and reference preservation, reserves specific property names (for example, `$type`, `$id`, and `$ref`) for emitting metadata. Previously, the serializer didn't perform validation on whether these property names conflicted with user-defined contracts, which could result in duplicate properties and produce JSON that was ambiguous or failed to round-trip. Starting with .NET 10, System.Text.Json enables validation to prevent such configurations and provides early warning to users. + +## Version introduced + +.NET 10 + +## Previous behavior + +Previously, the following code produced an invalid JSON object with duplicate `Type` properties and failed to deserialize with a : + +```csharp +using System.Text.Json; +using System.Text.Json.Serialization; + +string json = JsonSerializer.Serialize(new Dog()); +Console.WriteLine(json); // {"Type":"dog","Type":"Dog"} +JsonSerializer.Deserialize(json); // JsonException: Deserialized object contains a duplicate 'Type' metadata property. + +[JsonPolymorphic(TypeDiscriminatorPropertyName = "Type")] +[JsonDerivedType(typeof(Dog), "dog")] +public abstract class Animal +{ + public abstract string Type { get; } +} + +public class Dog : Animal +{ + public override string Type => "Dog"; +} +``` + +## New behavior + +Starting in .NET 10, any attempt to serialize that same type results in an early validation error: + +> InvalidOperationException: The type 'Dog' contains property 'Type' that conflicts with an existing metadata property name. Consider either renaming it or ignoring it with JsonIgnoreAttribute. + +This validation error occurs when the serializer is first created or when serialization is first attempted, providing early detection of invalid serialization contracts. + +## Type of breaking change + +This change is a [behavioral change](../../categories.md#behavioral-change). + +## Reason for change + +This change provides early prevention of invalid serialization contracts. By validating property names upfront, the serializer prevents scenarios where duplicate properties would be emitted, resulting in invalid JSON that cannot round-trip correctly. This helps developers identify and fix configuration issues during development rather than discovering them at run time during deserialization. + +For more information, see: + +- [[STJ] Disallow property names that conflict with metadata property names (dotnet/runtime#106390)](https://github.com/dotnet/runtime/issues/106390) +- [Disallow types with property names conflicting with metadata (dotnet/runtime#106460)](https://github.com/dotnet/runtime/pull/106460) + +## Recommended action + +Avoid using property names that conflict with System.Text.Json-specific metadata properties (such as `$type`, `$id`, and `$ref`). If it's absolutely necessary to keep such a property in the class, apply a annotation on the conflicting property. + +## Affected APIs + +- +- +- diff --git a/docs/core/compatibility/toc.yml b/docs/core/compatibility/toc.yml index 88af8c7d6571b..aadc279515248 100644 --- a/docs/core/compatibility/toc.yml +++ b/docs/core/compatibility/toc.yml @@ -172,8 +172,8 @@ items: href: sdk/10.0/prune-packagereference-privateassets.md - name: Serialization items: - - name: System.Text.Json validates property names conflicting with metadata properties - href: serialization/10/json-validates-metadata-property-names.md + - name: System.Text.Json checks for property name conflicts + href: serialization/10/property-name-validation.md - name: XmlSerializer no longer ignores properties marked with ObsoleteAttribute href: serialization/10/xmlserializer-obsolete-properties.md - name: Windows Forms From 22f206a0e124b06eb71ed25593922fb70362fd1d Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Thu, 13 Nov 2025 10:04:04 -0800 Subject: [PATCH 5/6] Update docs/core/compatibility/serialization/10/property-name-validation.md --- .../compatibility/serialization/10/property-name-validation.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/core/compatibility/serialization/10/property-name-validation.md b/docs/core/compatibility/serialization/10/property-name-validation.md index 876ca60da30fc..4a352ad5730f6 100644 --- a/docs/core/compatibility/serialization/10/property-name-validation.md +++ b/docs/core/compatibility/serialization/10/property-name-validation.md @@ -64,6 +64,5 @@ Avoid using property names that conflict with System.Text.Json-specific metadata ## Affected APIs -- - - From 762a035b87e52fa0073957fbe0fee6bd8a64985b Mon Sep 17 00:00:00 2001 From: Genevieve Warren <24882762+gewarren@users.noreply.github.com> Date: Thu, 13 Nov 2025 10:59:04 -0800 Subject: [PATCH 6/6] Update docs/core/compatibility/serialization/10/property-name-validation.md Co-authored-by: Jeff Handley --- .../compatibility/serialization/10/property-name-validation.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/core/compatibility/serialization/10/property-name-validation.md b/docs/core/compatibility/serialization/10/property-name-validation.md index 4a352ad5730f6..204500dd2c68c 100644 --- a/docs/core/compatibility/serialization/10/property-name-validation.md +++ b/docs/core/compatibility/serialization/10/property-name-validation.md @@ -6,7 +6,7 @@ ai-usage: ai-assisted --- # System.Text.Json checks for property name conflicts -Under certain contexts, such as polymorphism and reference preservation, reserves specific property names (for example, `$type`, `$id`, and `$ref`) for emitting metadata. Previously, the serializer didn't perform validation on whether these property names conflicted with user-defined contracts, which could result in duplicate properties and produce JSON that was ambiguous or failed to round-trip. Starting with .NET 10, System.Text.Json enables validation to prevent such configurations and provides early warning to users. +Under certain contexts, such as polymorphism and reference preservation, reserves specific property names (for example, `$type`, `$id`, and `$ref`) for emitting metadata. Some property names such as the `TypeDiscriminatorPropertyName` can also be configured with custom names. Previously, the serializer didn't perform validation on whether these property names conflicted with user-defined contracts, which could result in duplicate properties and produce JSON that was ambiguous or failed to round-trip. Starting with .NET 10, System.Text.Json enables validation to prevent such configurations and provides early warning to users. ## Version introduced