Skip to content

[Bug]: Avoid duplicate output for required nullable properties during patch serialization #11082

Description

@joseharriaga

Describe the bug

For properties defined as required but nullable (foo: string | null), the generated C# serialization code can emit the property twice during serialization when using JsonPatch. The generated pattern writes either the value or null for the property before Patch.WriteTo(writer) runs, so when the patch also contains that same property path, the patched value is emitted again, resulting in duplicate JSON properties.

The property serialization fallback should only execute when the patch does not already contain the property path. In practice, the null/value branch for a required nullable property should be gated on !Patch.Contains("$.param") so patched values are the single source of output for that property.

Reproduction

Relevant generated code pattern:

if (Optional.IsDefined(Foo) && !Patch.Contains("$.foo"u8))
{
    writer.WritePropertyName("foo"u8);
    writer.WriteStringValue(Foo);
}
else
{
    writer.WriteNull("foo"u8);
}

This else branch still writes "foo": null even when Patch.Contains("$.foo") is true. Later, Patch.WriteTo(writer) emits the patched foo value, producing duplicate foo properties.

Expected behavior:

  • When Patch.Contains("$.foo") is true, neither the value branch nor the null fallback should write foo directly.
  • The generated serialization should instead let Patch.WriteTo(writer) emit the property exactly once.

Likely generator location:

  • packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/src/Providers/MrwSerializationTypeDefinition.cs

Related generated/test files showing merge-patch patterns:

  • packages/http-client-csharp/generator/TestProjects/Local/Sample-TypeSpec/src/Generated/Models/DynamicModel.Serialization.cs
  • packages/http-client-csharp/generator/Microsoft.TypeSpec.Generator.ClientModel/test/Providers/MrwSerializationTypeDefinitions/TestData/DynamicModelSerializationTests/WriteMultiplePrimitiveProperties.cs

A minimal repro is a model with a required nullable property such as foo: string | null, where the property is included in Patch and serialization is generated using the current C# client model generator.

Checklist

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingemitter:client:csharpIssue for the C# client emitter: @typespec/http-client-csharp

    Type

    No fields configured for Bug.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions