microsoft/aspire · error · JsonException
Missing 'type' property.
Error message
Missing 'type' property.
What it means
GenAIMessages custom converter Read parses the whole message into a JsonDocument and requires a discriminator "type" property to pick the concrete MessagePart. If the property is absent the JSON does not conform to the GenAI message-part union schema, so JsonException("Missing 'type' property.") is thrown.
Solutions
- Add the "type" discriminator to every message part (e.g. "text", "functionCall", "functionResult", "media") before serializing
- Upgrade the emitting instrumentation to a version that writes the standard GenAI content schema
- Inspect the telemetry attribute containing the message body and fix its structure at the source
- If integrating a custom schema, pre-map your format to the expected {type, ...} shape before deserialization
Example fix
// before
{"text": "hello"}
// after
{"type": "text", "text": "hello"} Defensive patterns
Strategy: validation
Validate before calling
using var doc = JsonDocument.Parse(json);
if (!doc.RootElement.TryGetProperty("type", out var t) || t.ValueKind != JsonValueKind.String)
throw new FormatException("Message part requires a string 'type' discriminator."); Type guard
static bool IsTypedMessagePart(JsonElement e) =>
e.ValueKind == JsonValueKind.Object &&
e.TryGetProperty("type", out var t) &&
t.ValueKind == JsonValueKind.String; Try / catch
try { part = JsonSerializer.Deserialize<MessagePart>(json, jsonTypeInfo); }
catch (JsonException ex) when (ex.Message.Contains("Missing 'type' property"))
{
logger.LogWarning(ex, "Message part missing type discriminator.");
} Prevention
- Always include "type" on every message part you serialize
- Upgrade emitting instrumentation to the current GenAI content schema
- Add schema tests for telemetry payloads produced by your app
When it happens
Trigger: Deserializing a message part object that lacks the discriminator, e.g. {"text":"hi"} instead of {"type":"text","text":"hi"}; feeding arbitrary JSON into GenAI message deserialization from telemetry attributes.
Common situations: Instrumentation emitting an older or custom GenAI content schema without the type field; hand-built payloads in tests or imports; vendor-specific extensions replacing the standard part shape.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- Expected start of chat message object.
- Error deserializing GenAI message content. Error description
- Expected a JSON array.
- Expected property name.
- The configuration file
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/2caf97412143288d.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Dashboard/Model/GenAI/GenAIMessages.cs:216
public string? Name { get; set; }
public string? Description { get; set; }
internal ToolDefinitionSchema? Parameters { get; set; }
}
/// <summary>
/// Handles polymorphic serialization and deserialization of <see cref="MessagePart"/> types.
/// </summary>
internal sealed class MessagePartConverter : JsonConverter<MessagePart>
{
public override MessagePart? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
using var doc = JsonDocument.ParseValue(ref reader);
string? type = null;
try
{
if (!doc.RootElement.TryGetProperty("type", out var typeProp))
{
throw new JsonException("Missing 'type' property.");
}
type = typeProp.GetString();
return type switch
{
MessagePart.TextType => doc.RootElement.Deserialize<TextPart>(options),
MessagePart.ToolCallType => TryParseStringArguments(doc.RootElement.Deserialize<ToolCallRequestPart>(options)),
MessagePart.ToolCallResponseType => doc.RootElement.Deserialize<ToolCallResponsePart>(options),
MessagePart.BlobType => doc.RootElement.Deserialize<BlobPart>(options),
MessagePart.FileType => doc.RootElement.Deserialize<FilePart>(options),
MessagePart.UriType => doc.RootElement.Deserialize<UriPart>(options),
MessagePart.ReasoningType => doc.RootElement.Deserialize<ReasoningPart>(options),
MessagePart.ServerToolCallType => TryParseServerToolCallArguments(doc.RootElement.Deserialize<ServerToolCallPart>(options)),
MessagePart.ServerToolCallResponseType => doc.RootElement.Deserialize<ServerToolCallResponsePart>(options),
_ => doc.RootElement.Deserialize<GenericPart>(options),
};
}View on GitHub (pinned to 25830f84bd)