microsoft/aspire · error
aspire: returned unexpected type %T
Error message
aspire: {capability.CapabilityId} returned unexpected type %T What it means
Generated Go capability methods invoke the capability over the socket and then assert the returned value has the expected Go type. If the remote side returns something of a different concrete type, the type assertion fails and this error is stored on the errored builder. It signals a protocol/shape mismatch between the AppHost and the generated client.
Solutions
- Regenerate the Go client from the current AppHost so return types match the live capability contract
- Upgrade the AppHost/CLI and Go client to matching versions
- Inspect the server-side capability implementation to confirm it returns the declared type
Defensive patterns
Strategy: try-catch
Try / catch
result, err := client.SomeCapability(ctx, arg)
if err != nil {
// covers type-mismatch errors stored by setErr
return fmt.Errorf("capability call failed: %w", err)
} Prevention
- Keep the AppHost and generated Go client versions in lockstep
- Regenerate the client after any capability return-type change
- Log %T of results when debugging protocol mismatches
When it happens
Trigger: A capability invoked via a generated method (with a declared return type) returns a value whose Go concrete type does not match the generated returnGoType assertion.
Common situations: Mismatched versions of the AppHost and the generated Go client (contract drift), a server-side bug returning nil or a different handle type, or custom/patched capability implementations.
Related errors
- aspire: build returned unexpected type %T
- aspire: createBuilder returned unexpected type %T
- no input with name ' ' was found
- argument ' ' passed to capability ' ' contains a circular…
- aspire: deep update recursion limit of '32' exceeded
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/82ffa23c683588ab.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.CodeGeneration.Go/AtsGoCodeGenerator.cs:1310
? implTarget
: null;
if (childImplName is null)
{
// No registered impl for this typeId (e.g. *ReferenceExpression,
// which is hand-written in base.go). Cast the wrapIfHandle result
// directly to the declared return type. Errors land on s; we
// return nil and the caller must consult s.Err().
var returnGoType = MapTypeRefToGo(returnType, false);
WriteLine("\tif s.err != nil { return nil }");
EmitHandleParamErrorChecks("\t", capability, "s.setErr(err); return nil");
EmitUnionTypeChecks("\t", capability, methodName, new[] { "s.setErr(err); return nil" });
EmitArgsConstruction("\t", capability, requiredParams, optionalParams, targetParamName, "s.handle");
WriteLine($"\tresult, err := s.client.invokeCapability(ctx, \"{capability.CapabilityId}\", reqArgs)");
WriteLine("\tif err != nil { s.setErr(err); return nil }");
WriteLine($"\ttyped, ok := result.({returnGoType})");
WriteLine("\tif !ok {");
WriteLine($"\t\ts.setErr(fmt.Errorf(\"aspire: {capability.CapabilityId} returned unexpected type %T\", result))");
WriteLine("\t\treturn nil");
WriteLine("\t}");
WriteLine("\treturn typed");
return;
}
// Pre-errored child path: parent failure short-circuits this call.
WriteLine($"\tif s.err != nil {{ return &{childImplName}{{resourceBuilderBase: newErroredResourceBuilder(s.err, s.client)}} }}");
EmitHandleParamErrorChecks("\t", capability,
$"return &{childImplName}{{resourceBuilderBase: newErroredResourceBuilder(err, s.client)}}");
EmitUnionTypeChecks("\t", capability, methodName, new[]
{
$"return &{childImplName}{{resourceBuilderBase: newErroredResourceBuilder(err, s.client)}}",
});
EmitArgsConstruction("\t", capability, requiredParams, optionalParams, targetParamName, "s.handle");
WriteLine($"\tresult, err := s.client.invokeCapability(ctx, \"{capability.CapabilityId}\", reqArgs)");
WriteLine("\tif err != nil {");
WriteLine($"\t\treturn &{childImplName}{{resourceBuilderBase: newErroredResourceBuilder(err, s.client)}}");View on GitHub (pinned to 25830f84bd)