microsoft/aspire · error · InvalidOperationException
Unknown type category
Error message
Unknown type category: {typeRef.Category} What it means
AtsMarshaller.MarshalToJson serializes a .NET value to JSON for the guest based on the AtsTypeRef's category. Each known category (Primitive, Enum, Dto, Array, List, Dict) has a dedicated branch; this throw is the exhaustive-match fallback, meaning the category value was not one of the recognized enum members. It signals an internal invariant violation: a new AtsTypeCategory member was added without updating the marshaller, or an uninitialized/corrupt category reached the switch.
Solutions
- Update/redeploy the host assembly so its marshaller knows the category used by the type reference (matching version).
- Check that the AtsTypeRef being marshalled was correctly registered/initialized (not a default value).
- Pin host and guest to the same Ats package version so categories match.
- If you control the code, add a case for the missing category in the switch expression.
Defensive patterns
Strategy: validation
Validate before calling
if (!Enum.IsDefined(typeof(AtsTypeCategory), typeRef.Category))
throw new InvalidOperationException($"Category {typeRef.Category} is not marshalled by this host version."); Type guard
static bool IsKnownCategory(AtsTypeRef t) =>
t.Category is AtsTypeCategory.Primitive or AtsTypeCategory.Enum or AtsTypeCategory.Dto
or AtsTypeCategory.Array or AtsTypeCategory.List or AtsTypeCategory.Dict; Prevention
- Keep the AtsTypeCategory switch exhaustive so the compiler flags unhandled enum members.
- Keep host and guest type-reference contracts on the same package version.
- Avoid marshalling default(AtsTypeRef) / uninitialized category values.
When it happens
Trigger: Calling MarshalToJson with a typeRef whose Category is not one of AtsTypeCategory.Primitive/Enum/Dto/Array/List/Dict (e.g. a newer category enum value marshalled by an older remote host assembly, or a default(AtsTypeRef) with an undefined category). Reached via SerializeArray -> MarshalToJson when recursing into array element types.
Common situations: Version skew where a guest sends a type reference using a newer AtsTypeCategory than the host's marshaller supports; a newly added AtsTypeCategory enum member whose branch was not implemented; corrupted or default-initialized AtsTypeRef values crossing the remote boundary.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Argument ' ' passed to capability ' ' contains a circular…
- aspire: returned unexpected type %T
- Aspire.Hosting/Dict.toObject only supports string-key…
- AspireDict must be resolved before it can be serialized…
- AspireList must be resolved before it can be serialized…
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/a2962eefb47de696.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.RemoteHost/Ats/AtsMarshaller.cs:164
return SerializeCancellationToken(cancellationToken);
}
// Handle 'any' type - fall back to runtime type inspection
if (typeRef.TypeId == TypeSystem.AtsConstants.Any)
{
return MarshalToJson(value);
}
return typeRef.Category switch
{
AtsTypeCategory.Handle => _handles.Marshal(value, typeRef.TypeId),
AtsTypeCategory.Primitive => SerializePrimitive(value),
AtsTypeCategory.Enum => JsonValue.Create(value.ToString()),
AtsTypeCategory.Dto => SerializeDto(value),
AtsTypeCategory.Array => SerializeArray(value, typeRef.ElementType),
AtsTypeCategory.List => _handles.Marshal(value, typeRef.TypeId),
AtsTypeCategory.Dict => _handles.Marshal(value, typeRef.TypeId),
_ => throw new InvalidOperationException($"Unknown type category: {typeRef.Category}")
};
}
/// <summary>
/// Marshals a .NET object to JSON for sending to the guest using a declared CLR type.
/// </summary>
/// <param name="value">The value to marshal.</param>
/// <param name="declaredType">The declared type that should be exposed to the guest.</param>
/// <returns>The JSON representation, or null if the value is null.</returns>
public JsonNode? MarshalToJson(object? value, Type declaredType)
{
if (value == null)
{
return null;
}
if (declaredType == typeof(object))
{View on GitHub (pinned to 25830f84bd)