microsoft/aspire · error · InvalidOperationException
Union input types must define at least one member type.
Error message
Union input types must define at least one member type.
What it means
MapInputUnionTypeToTypeScript maps an input union type reference to TypeScript. A union with a null or empty UnionTypes list cannot produce any member types, so the projector throws this InvalidOperationException as a validation guard before building the union.
Solutions
- Populate typeRef.UnionTypes with at least one member AtsTypeRef before projecting.
- Fix the analyzer/builder that produced the empty union (usually means it failed to resolve member types).
- If the type is genuinely not a union, construct a plain type ref instead of an empty union.
- Log the offending typeId to locate where the incomplete AtsTypeRef was created.
Example fix
// before
var typeRef = new AtsTypeRef { UnionTypes = new List<AtsTypeRef>() }; // empty union
var ts = projector.MapInputUnionTypeToTypeScript(typeRef); // throws
// after
typeRef.UnionTypes.Add(new AtsTypeRef { /* string member */ });
typeRef.UnionTypes.Add(new AtsTypeRef { /* number member */ });
var ts = projector.MapInputUnionTypeToTypeScript(typeRef); // "string | number" Defensive patterns
Strategy: validation
Validate before calling
if (typeRef.UnionTypes is not { Count: > 0 }) {
throw new InvalidOperationException("populate UnionTypes with at least one member before mapping");
} Try / catch
try {
var ts = MapInputUnionTypeToTypeScript(typeRef);
} catch (InvalidOperationException ex) when (ex.Message.Contains("at least one member")) {
// fix the builder that produced the empty union and retry
throw;
} Prevention
- Always add at least one member when constructing a union type ref.
- Fix resolvers that silently emit empty unions when member types fail to resolve.
- Use plain type refs for non-union types instead of empty unions.
- Add model validation after building AtsTypeRef instances.
When it happens
Trigger: Building an input type projection from an AtsTypeRef whose UnionTypes collection is null or has zero entries — e.g. an API model constructed with a union but no member types added, or deserialized model with an empty union list.
Common situations: Builder code creates an AtsTypeRef for a union but forgets to call Add on UnionTypes; a custom analyzer produces an empty union for a type it could not resolve; hand-edited or deserialized metadata lost the member list.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- -32602
- Enum type ' ' was not found in the scanned enum types. This…
- The certificate bundle cache file prefix contains invalid…
- A step with the name
- A validation message must be provided for a failed…
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/0d08a3f83ac05223.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.CodeGeneration.TypeScript/TypeScriptApiProjector.cs:1898
if (typeRef?.TypeId == InteractionInputCollectionTypeId)
{
return $"Awaitable<{GetInteractionInputCollectionClassName()}>";
}
if (IsCancellationTokenType(typeRef))
{
return $"AbortSignal | {GetCancellationTokenInterfaceName()}";
}
return MapTypeRefToTypeScript(typeRef);
}
internal string MapInputUnionTypeToTypeScript(AtsTypeRef typeRef)
{
if (typeRef.UnionTypes == null || typeRef.UnionTypes.Count == 0)
{
throw new InvalidOperationException("Union input types must define at least one member type.");
}
// Build union structurally: each member is mapped individually.
// Handle types become Awaitable<T>, non-handle types pass through as-is.
var nonHandleTypes = new List<string>();
var handleTypeNames = new List<string>();
foreach (var memberRef in typeRef.UnionTypes)
{
if (IsWidenedHandleType(memberRef))
{
// Get the base type name without Awaitable wrapper for combining
var baseName = IsInterfaceHandleType(memberRef) && TryMapInterfaceInputTypeToTypeScript(memberRef) is { } expanded
? expanded
: MapTypeRefToTypeScript(memberRef);
nonHandleTypes.Add(baseName);
handleTypeNames.Add(baseName);
}View on GitHub (pinned to 25830f84bd)