{"record":{"id":"162cbffa7bb0987d","repo":"microsoft/aspire","slug":"ex-message-rethrown-wrapped-as-invalidoperationexception","errorCode":null,"errorMessage":"ex.Message (rethrown wrapped as InvalidOperationException with original exception as inner)","messagePattern":"ex\\.Message \\(rethrown wrapped as InvalidOperationException with original exception as inner\\)","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/Aspire.Hosting.RemoteHost/Ats/CapabilityDispatcher.cs","lineNumber":672,"sourceCode":"                return null;\n            }\n\n            if (returnType.IsGenericType && returnType.GetGenericTypeDefinition() == typeof(ValueTask<>))\n            {\n                var asTask = returnType.GetMethod(nameof(ValueTask<int>.AsTask), BindingFlags.Instance | BindingFlags.Public)\n                    ?? throw new InvalidOperationException($\"Unable to await ValueTask result for return type '{returnType}'.\");\n                var boxedTask = asTask.Invoke(result, null) as Task\n                    ?? throw new InvalidOperationException($\"Unable to convert ValueTask result for return type '{returnType}' to Task.\");\n\n                await boxedTask.ConfigureAwait(false);\n                return GetAsyncResultValue(boxedTask);\n            }\n\n            return result;\n        }\n        catch (Exception ex) when (ex is not InvalidOperationException)\n        {\n            throw new InvalidOperationException(ex.Message, ex);\n        }\n    }\n\n    private static object? GetAsyncResultValue(Task task)\n    {\n        var taskType = task.GetType();\n        if (!taskType.IsGenericType)\n        {\n            return null;\n        }\n\n        var resultProperty = taskType.GetProperty(\"Result\");\n        return resultProperty?.GetValue(task);\n    }\n\n    private static object? InvokeMethodCore(MethodInfo method, object? target, object?[] methodArgs)\n    {\n        return method.Invoke(target, methodArgs);","sourceCodeStart":654,"sourceCodeEnd":690,"githubUrl":"https://github.com/microsoft/aspire/blob/25830f84bd145686607ad00c057b3f84e2e51d43/src/Aspire.Hosting.RemoteHost/Ats/CapabilityDispatcher.cs#L654-L690","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ntry { await dispatcher.InvokeAsync(...); }\ncatch (InvalidOperationException ex) { Log(ex.Message); }\n\n// after\ntry { await dispatcher.InvokeAsync(...); }\ncatch (InvalidOperationException ex) when (ex.InnerException is { } inner)\n{\n    Log($\"{ex.Message} <- {inner.GetType().Name}: {inner.Message}\");\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try\n{\n    var result = await dispatcher.InvokeAsync(capability, args);\n}\ncatch (InvalidOperationException ex)\n{\n    var root = UnwrapToRoot(ex); // walk InnerException chain\n    logger.LogError(root, \"Remote capability invocation failed: {Root}\", root.Message);\n}","preventionTips":["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."],"tags":["exception-wrapping","remote-host","reflection"],"backgroundTag":"internal-invariant-violation","analyzedSha":"25830f84bd145686607ad00c057b3f84e2e51d43","analyzedAt":"2026-09-16T11:10:06.193Z","contentChangedAt":"2026-09-16T11:10:06.193Z","schemaVersion":2},"datasetVersion":"2026-09-21T04:17:39.646Z"}