Skip to content

[http-client-csharp] Optional nullable properties cannot emit explicit JSON null #11970

Description

@JoshLove-msft

Description

The C# emitter collapses an optional nullable property's omitted and explicitly null states. Setting the generated property to null omits it from the request instead of writing JSON null.

This breaks services where omission selects a default but explicit null disables a feature. For example, Foundry voice-agent turn detection defaults to enabled and requires "turn_detection": null to disable it.

Input and reproduction

The pinned TypeSpec declarations correctly model both optionality and nullability:

noise_reduction?: VoiceAgentNoiseReduction | null;
turn_detection?: VoiceAgentTurnDetectionConfig | null;
transcription?: VoiceAgentInputTranscription | null;

Using the generated model in Azure/azure-sdk-for-net#62884:

using System;
using System.ClientModel.Primitives;
using Azure.AI.Projects.Agents;

#pragma warning disable AAIP001
var input = new VoiceAgentAudioInputConfig
{
    TurnDetection = null
};

Console.WriteLine(ModelReaderWriter.Write(
    input,
    new ModelReaderWriterOptions("W"),
    AzureAIProjectsAgentsContext.Default).ToString());

Actual: {}

Expected: {"turn_detection":null}

Leaving TurnDetection unset should still produce {}. The generated model needs to preserve the distinction rather than serializing all unset nullable properties as null.

The same omission occurs for NoiseReduction and Transcription. Serialization through the containing voice-agent definition produces "audio":{"input":{}}, so this also affects actual agent request bodies. The omission was reproduced against the compiled SDK and its real dependencies without service calls.

Upstream implementation

In the pinned generator, MrwSerializationTypeDefinition.CreateConditionalSerializationStatement uses Optional.IsDefined(property) and generates an explicit-null branch only for isRequired && isNullable. Optional nullable properties fall through to an if (IsDefined(...)) guard, and these generated reference-type properties have no explicit-presence tracking.

The SDK's active custom visitors only add experimental attributes or adjust virtual/override modifiers; they do not change these property types or serialization conditions.

Environment

Expected coverage

Please cover omitted, explicitly null, and non-null values for optional nullable model properties, including nested wire serialization and preservation of explicit null when reading and then writing a model.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions