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

  1. Inspect ex.InnerException (or the full stack trace) to find the original failure; the outer message is just a rewrap.
  2. Fix the underlying handler so it does not throw during result unwrapping.
  3. If you need the original type for catch logic, unwrap: catch InvalidOperationException and check its InnerException.
  4. 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

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


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)