microsoft/aspire · error · InvalidOperationException
ex.Message (rethrown wrapped as InvalidOperationException…
Error message
ex.Message (rethrown wrapped as InvalidOperationException with original exception as inner)
What it means
UnwrapAsyncResultAsync wraps any exception that is not already an InvalidOperationException into a new InvalidOperationException with the original message and original exception as InnerException. This is a normalization step so the remote-host protocol always surfaces dispatcher failures as a single exception type; the real cause is in the inner exception.
Solutions
- Inspect ex.InnerException (or the full stack trace) to find the original failure; the outer message is just a rewrap.
- Fix the underlying handler so it does not throw during result unwrapping.
- If you need the original type for catch logic, unwrap: catch InvalidOperationException and check its InnerException.
- Keep handler exceptions as InvalidOperationException if you want them to pass through unwrapped.
Example fix
// before
try { await dispatcher.InvokeAsync(...); }
catch (InvalidOperationException ex) { Log(ex.Message); }
// after
try { await dispatcher.InvokeAsync(...); }
catch (InvalidOperationException ex) when (ex.InnerException is { } inner)
{
Log($"{ex.Message} <- {inner.GetType().Name}: {inner.Message}");
} Defensive patterns
Strategy: try-catch
Try / catch
try
{
var result = await dispatcher.InvokeAsync(capability, args);
}
catch (InvalidOperationException ex)
{
var root = UnwrapToRoot(ex); // walk InnerException chain
logger.LogError(root, "Remote capability invocation failed: {Root}", root.Message);
} Prevention
- Always log InnerException for InvalidOperationException from the dispatcher.
- Write a shared unwrap helper instead of inspecting outer messages.
- Keep handler-side exceptions as InvalidOperationException when you need pass-through semantics.
- Add handler-level try/catch to convert domain errors before they reach the unwrap path.
When it happens
Trigger: Any failure inside the result-unwrap path — reflection TargetInvocationException from invoking AsTask/Build, InvalidCastException from GetAsyncResultValue, or a handler-thrown exception — is caught by the `when (ex is not InvalidOperationException)` filter and rethrown wrapped.
Common situations: A handler throws mid-execution; a return-type reflection invoke fails after an assembly version change; debugging a remote capability call and seeing only the wrapper message in logs.
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
- Unable to convert ValueTask result for return type
- argument ' ' passed to capability ' ' contains a circular…
- aspire: merge type mismatch: cannot merge
- AspireValueAttribute requires a catalog name.
- ' .Build()' returned null.
AI-assisted analysis of microsoft/aspire@25830f84bd (2026-09-16).
Data as JSON: /api/errors/162cbffa7bb0987d.
Report an issue: GitHub.
Appendix: source
Thrown at src/Aspire.Hosting.RemoteHost/Ats/CapabilityDispatcher.cs:672
return null;
}
if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(ValueTask<>))
{
var asTask = returnType.GetMethod(nameof(ValueTask<int>.AsTask), BindingFlags.Instance | BindingFlags.Public)
?? throw new InvalidOperationException($"Unable to await ValueTask result for return type '{returnType}'.");
var boxedTask = asTask.Invoke(result, null) as Task
?? throw new InvalidOperationException($"Unable to convert ValueTask result for return type '{returnType}' to Task.");
await boxedTask.ConfigureAwait(false);
return GetAsyncResultValue(boxedTask);
}
return result;
}
catch (Exception ex) when (ex is not InvalidOperationException)
{
throw new InvalidOperationException(ex.Message, ex);
}
}
private static object? GetAsyncResultValue(Task task)
{
var taskType = task.GetType();
if (!taskType.IsGenericType)
{
return null;
}
var resultProperty = taskType.GetProperty("Result");
return resultProperty?.GetValue(task);
}
private static object? InvokeMethodCore(MethodInfo method, object? target, object?[] methodArgs)
{
return method.Invoke(target, methodArgs);View on GitHub (pinned to 25830f84bd)