{"record":{"id":"2caf97412143288d","repo":"microsoft/aspire","slug":"missing-type-property","errorCode":null,"errorMessage":"Missing 'type' property.","messagePattern":"Missing 'type' property\\.","errorType":"exception","errorClass":"JsonException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Dashboard/Model/GenAI/GenAIMessages.cs","lineNumber":216,"sourceCode":"    public string? Name { get; set; }\n    public string? Description { get; set; }\n    internal ToolDefinitionSchema? Parameters { get; set; }\n}\n\n/// <summary>\n/// Handles polymorphic serialization and deserialization of <see cref=\"MessagePart\"/> types.\n/// </summary>\ninternal sealed class MessagePartConverter : JsonConverter<MessagePart>\n{\n    public override MessagePart? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)\n    {\n        using var doc = JsonDocument.ParseValue(ref reader);\n        string? type = null;\n        try\n        {\n            if (!doc.RootElement.TryGetProperty(\"type\", out var typeProp))\n            {\n                throw new JsonException(\"Missing 'type' property.\");\n            }\n\n            type = typeProp.GetString();\n\n            return type switch\n            {\n                MessagePart.TextType => doc.RootElement.Deserialize<TextPart>(options),\n                MessagePart.ToolCallType => TryParseStringArguments(doc.RootElement.Deserialize<ToolCallRequestPart>(options)),\n                MessagePart.ToolCallResponseType => doc.RootElement.Deserialize<ToolCallResponsePart>(options),\n                MessagePart.BlobType => doc.RootElement.Deserialize<BlobPart>(options),\n                MessagePart.FileType => doc.RootElement.Deserialize<FilePart>(options),\n                MessagePart.UriType => doc.RootElement.Deserialize<UriPart>(options),\n                MessagePart.ReasoningType => doc.RootElement.Deserialize<ReasoningPart>(options),\n                MessagePart.ServerToolCallType => TryParseServerToolCallArguments(doc.RootElement.Deserialize<ServerToolCallPart>(options)),\n                MessagePart.ServerToolCallResponseType => doc.RootElement.Deserialize<ServerToolCallResponsePart>(options),\n                _ => doc.RootElement.Deserialize<GenericPart>(options),\n            };\n        }","sourceCodeStart":198,"sourceCodeEnd":234,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Dashboard/Model/GenAI/GenAIMessages.cs#L198-L234","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n{\"text\": \"hello\"}\n// after\n{\"type\": \"text\", \"text\": \"hello\"}","handlingStrategy":"validation","validationCode":"using var doc = JsonDocument.Parse(json);\nif (!doc.RootElement.TryGetProperty(\"type\", out var t) || t.ValueKind != JsonValueKind.String)\n    throw new FormatException(\"Message part requires a string 'type' discriminator.\");","typeGuard":"static bool IsTypedMessagePart(JsonElement e) =>\n    e.ValueKind == JsonValueKind.Object &&\n    e.TryGetProperty(\"type\", out var t) &&\n    t.ValueKind == JsonValueKind.String;","tryCatchPattern":"try { part = JsonSerializer.Deserialize<MessagePart>(json, jsonTypeInfo); }\ncatch (JsonException ex) when (ex.Message.Contains(\"Missing 'type' property\"))\n{\n    logger.LogWarning(ex, \"Message part missing type discriminator.\");\n}","preventionTips":["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"],"tags":["json","discriminator","genai","schema"],"backgroundTag":"schema-validation-failed","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}