Skip to content

.NET: [Bug]: AddAGUIServer writes explicit nulls on the AG-UI wire with AGUI 0.0.6 (rejected by @ag-ui/client) #7919

Closed

Description

@LoicDagnas

Description

AddAGUIServer() registers the AG-UI wire types through AGUIJsonSerializerContext.Default.Options.TypeInfoResolver. AGUI 0.0.6 moved the "omit a property that has no value" rule off that resolver. In 0.0.5 the rule came from DefaultIgnoreCondition on the context's own options; in 0.0.6 it lives on the new AGUIJsonUtilities.DefaultTypeInfoResolver, which applies it per property with a type-info modifier so it travels with the resolver into other JsonSerializerOptions.

The consequence, for an app on hosting 1.17–1.19 with AGUI.Server / AGUI.Abstractions raised to 0.0.6, is that every SSE event goes out with explicit nulls for its optional fields:

data: {"type":"RUN_STARTED","threadId":"…","runId":"…","parentRunId":null,"input":null,"timestamp":null,"rawEvent":null,"metadata":null}

The AG-UI TypeScript client (@ag-ui/client 0.0.59) declares those fields optional, not nullable, so it rejects the first event and the whole run fails client-side:

ZodError: [
  { "code": "invalid_type", "expected": "string", "received": "null", "path": ["parentRunId"] },
  { "code": "invalid_type", "expected": "object", "received": "null", "path": ["input"] },
  …
]

AGUIJsonUtilities' own doc comment names this exact failure — "would start writing "parentMessageId": null and similar — the exact wire divergence that receiving SDKs have had to be patched to tolerate" — and tells integrators to compose AGUIJsonUtilities.DefaultTypeInfoResolver rather than the context directly.

This is not visible in this repo's own CI today because dotnet/Directory.Packages.props pins the AGUI packages at 0.0.5. It becomes the default behavior the moment that pin moves to 0.0.6.

Suggested fix — in ConfigureAGUIJsonOptions.Configure:

 chain.Add(AgentAbstractionsJsonUtilities.DefaultOptions.TypeInfoResolver!);
-chain.Add(AGUIJsonSerializerContext.Default.Options.TypeInfoResolver!);
+chain.Add(AGUIJsonUtilities.DefaultTypeInfoResolver);

AGUIJsonUtilities.DefaultTypeInfoResolver is AGUIJsonSerializerContext.Default with the omit-empty modifier attached, so it resolves the same types and only changes what is written for properties with no value. It is new in 0.0.6, so this line and the package bump have to land together.

Code Sample

var builder = WebApplication.CreateBuilder(args);
builder.Services.AddAGUIServer();
builder.AddAIAgent("agent", (sp, name) => new ChatClientAgent(chatClient, new ChatClientAgentOptions { Name = name }));

var app = builder.Build();
app.MapAGUIServer("/ag-ui", app.Services.GetRequiredKeyedService<AIAgent>("agent"));
app.Run();

With AGUI.Server / AGUI.Abstractions raised to 0.0.6, curl -N -H 'Accept: text/event-stream' … on that endpoint shows "timestamp": null, "metadata": null, "parentRunId": null and "input": null on the events. With 0.0.5 the same fields are omitted.

Workaround for anyone hitting this before the fix lands — put the modified resolver first in the chain, after AddAGUIServer():

builder.Services.Configure<JsonOptions>(options =>
    options.SerializerOptions.TypeInfoResolverChain.Insert(0, AGUIJsonUtilities.DefaultTypeInfoResolver));

Error Messages / Stack Traces

Agent execution failed: ZodError: [
  { "code": "invalid_type", "expected": "number", "received": "null", "path": ["timestamp"], "message": "Expected number, received null" },
  { "code": "invalid_type", "expected": "object", "received": "null", "path": ["metadata"], "message": "Expected object, received null" },
  { "code": "invalid_type", "expected": "string", "received": "null", "path": ["parentRunId"], "message": "Expected string, received null" },
  { "code": "invalid_type", "expected": "object", "received": "null", "path": ["input"], "message": "Expected object, received null" }
]

Package Versions

  • Microsoft.Agents.AI.Hosting.AGUI.AspNetCore 1.17.0-preview.260804.1 (the same code is in 1.19.0-preview.260822.1 and on main)
  • AGUI.Server / AGUI.Abstractions 0.0.6
  • Microsoft.Extensions.AI 10.8.3
  • Client: @ag-ui/client 0.0.59

.NET Version

net10.0

Additional Context

Both current hosting previews (1.17, 1.19) declare AGUI 0.0.5, so ConfigureAGUIJsonOptions and the AGUI package version have to move together for the wire format to stay unchanged.

Activity

  1. added
    .NETUsage: [Issues, PRs], Target: .Net
    triageUsage: [Issues], Target: All issues that still need to be triaged
    on Aug 27, 2026
  2. added
    reproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflow
    on Aug 31, 2026
  3. github-actions commented on Aug 31, 2026

    @github-actions
    Contributor

    🤖 Automated triage reproduction notes (agent-authored — trust but verify)

    Agent analysis

    Repro: dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/ConfigureAGUIJsonOptions.cs::ConfigureAGUIJsonOptions.Configure line 24 registers the raw AGUI resolver; with AGUI.Abstractions 0.0.6, serializing a RunStartedEvent through AddAGUIServer() JSON options emits explicit null optional fields. Minimal repro: override AGUI.Abstractions to 0.0.6, resolve JsonOptions after AddAGUIServer(), serialize a minimally populated RunStartedEvent, and assert that :null is absent; the test fails while 0.0.5 passes.

    • Failing test: dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/ConfigureAGUIJsonOptionsTests.cs
    • Files examined: dotnet/Directory.Packages.props, dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/ConfigureAGUIJsonOptions.cs, dotnet/src/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore/AGUIServerSentEventsResult.cs, dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/ConfigureAGUIJsonOptionsTests.cs, dotnet/tests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests/Microsoft.Agents.AI.Hosting.AGUI.AspNetCore.UnitTests.csproj, dotnet/nuget/nuget-package.props
    • Tests run: AddAGUIServer_WithAGUI006_OmitsNullOptionalEventProperties with AGUI.Abstractions 0.0.6 (failed), AddAGUIServer_WithAGUI006_OmitsNullOptionalEventProperties with AGUI.Abstractions 0.0.5 control (passed)
    • Reported version: 1.17.0-preview.260804.1
    • Current version: 1.20.0
  4. added
    ag-uiUsage: [Issues, PRs], Target: AG-UI protocol integration
    hostingUsage: [Issues, PRs], Target: all hosting related solutions
    and removed
    triageUsage: [Issues], Target: All issues that still need to be triaged
    on Aug 31, 2026
  5. petarnenov commented on Oct 2, 2026

    @petarnenov

    Still reproducible with Microsoft.Agents.AI.Hosting.AGUI.AspNetCore 1.23.0-preview.260928.1 with AGUI.* 1.0.0, against @ag-ui/client 1.0.1. ConfigureAGUIJsonOptions still appends AGUIJsonSerializerContext.Default's resolver rather than AGUIJsonUtilities.DefaultTypeInfoResolver. Details, and a related interrupt-serialization defect in the same method, are in #8962.

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

Metadata

Metadata

Labels

.NETUsage: [Issues, PRs], Target: .Netag-uiUsage: [Issues, PRs], Target: AG-UI protocol integrationhostingUsage: [Issues, PRs], Target: all hosting related solutionsreproducedUsage: [Issues], Target: all issues that can be reproduced by the triage workflow

Type

Projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions