[pigeon] Async error handling for kotlin and swift (#3102)

* temp

* sets up use of wrapError

* remove swift from skip list, update wrapError func

* changelog

* macos tests

* Stacktrace label

* nits

* async wont try, do, throw, or catch

* Async error handling

* throwAsyncError all but kotlin + c++

* conflicts

* typo

* }

* revert bad merge

* more try

* Revert "more try"

This reverts commit 2d80efeb07c3c166d6c2a651babadf5b520fef0f.

* kotlin

* kotlin wrapError, cpp attempt

* Fix Windows implementation

* adds async error from void method integration test

* changelog

* windows

* fix null returns on async kotlin

* nits

* nits

* typo

---------

Co-authored-by: Stuart Morgan <stuartmorgan@google.com>
diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md
index 9342499..b284eba 100644
--- a/packages/pigeon/CHANGELOG.md
+++ b/packages/pigeon/CHANGELOG.md
@@ -1,3 +1,13 @@
+## 7.2.0
+
+* [swift] Changes async method completion types. 
+  May require code updates to existing code.
+* [swift] Adds error handling to async methods.
+* [kotlin] Changes async method completion types. 
+  May require code updates to existing code.
+* [kotlin] Adds error handling to async methods.
+* Adds async error handling integration tests for all platforms.
+
 ## 7.1.5
 
 * Updates code to fix strict-cast violations.
diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart
index 757464e..481b97f 100644
--- a/packages/pigeon/lib/generator_tools.dart
+++ b/packages/pigeon/lib/generator_tools.dart
@@ -11,7 +11,7 @@
 /// The current version of pigeon.
 ///
 /// This must match the version in pubspec.yaml.
-const String pigeonVersion = '7.1.5';
+const String pigeonVersion = '7.2.0';
 
 /// Read all the content from [stdin] to a String.
 String readStdin() {
diff --git a/packages/pigeon/lib/kotlin_generator.dart b/packages/pigeon/lib/kotlin_generator.dart
index ec2f687..78eb2b1 100644
--- a/packages/pigeon/lib/kotlin_generator.dart
+++ b/packages/pigeon/lib/kotlin_generator.dart
@@ -440,11 +440,13 @@
             ? ''
             : _nullsafeKotlinTypeForDartType(method.returnType);
 
+        final String resultType =
+            method.returnType.isVoid ? 'Unit' : returnType;
         addDocumentationComments(
             indent, method.documentationComments, _docCommentSpec);
 
         if (method.isAsynchronous) {
-          argSignature.add('callback: ($returnType) -> Unit');
+          argSignature.add('callback: (Result<$resultType>) -> Unit');
           indent.writeln('fun ${method.name}(${argSignature.join(', ')})');
         } else if (method.returnType.isVoid) {
           indent.writeln('fun ${method.name}(${argSignature.join(', ')})');
@@ -501,43 +503,54 @@
                 indent.write('channel.setMessageHandler ');
                 indent.addScoped('{ $messageVarName, reply ->', '}', () {
                   indent.writeln('var wrapped = listOf<Any?>()');
-                  indent.write('try ');
-                  indent.addScoped('{', '}', () {
-                    final List<String> methodArgument = <String>[];
-                    if (method.arguments.isNotEmpty) {
-                      indent.writeln('val args = message as List<Any?>');
-                      enumerate(method.arguments, (int index, NamedType arg) {
-                        final String argName = _getSafeArgumentName(index, arg);
-                        final String argIndex = 'args[$index]';
-                        indent.writeln(
-                            'val $argName = ${_castForceUnwrap(argIndex, arg.type, root)}');
-                        methodArgument.add(argName);
+                  final List<String> methodArguments = <String>[];
+                  if (method.arguments.isNotEmpty) {
+                    indent.writeln('val args = message as List<Any?>');
+                    enumerate(method.arguments, (int index, NamedType arg) {
+                      final String argName = _getSafeArgumentName(index, arg);
+                      final String argIndex = 'args[$index]';
+                      indent.writeln(
+                          'val $argName = ${_castForceUnwrap(argIndex, arg.type, root)}');
+                      methodArguments.add(argName);
+                    });
+                  }
+                  final String call =
+                      'api.${method.name}(${methodArguments.join(', ')})';
+
+                  if (method.isAsynchronous) {
+                    indent.write('$call ');
+                    final String resultType = method.returnType.isVoid
+                        ? 'Unit'
+                        : _nullsafeKotlinTypeForDartType(method.returnType);
+                    indent.addScoped('{ result: Result<$resultType> ->', '}',
+                        () {
+                      indent.writeln('val error = result.exceptionOrNull()');
+                      indent.writeScoped('if (error != null) {', '}', () {
+                        indent.writeln('reply.reply(wrapError(error))');
+                      }, addTrailingNewline: false);
+                      indent.addScoped(' else {', '}', () {
+                        if (method.returnType.isVoid) {
+                          indent.writeln('reply.reply(wrapResult(null))');
+                        } else {
+                          indent.writeln('val data = result.getOrNull()');
+                          indent.writeln('reply.reply(wrapResult(data))');
+                        }
                       });
-                    }
-                    final String call =
-                        'api.${method.name}(${methodArgument.join(', ')})';
-                    if (method.isAsynchronous) {
-                      indent.write('$call ');
-                      final String resultValue =
-                          method.returnType.isVoid ? 'null' : 'it';
-                      indent.addScoped('{', '}', () {
-                        indent.writeln('reply.reply(wrapResult($resultValue))');
-                      });
-                    } else if (method.returnType.isVoid) {
-                      indent.writeln(call);
-                      indent.writeln('wrapped = listOf<Any?>(null)');
-                    } else {
-                      indent.writeln('wrapped = listOf<Any?>($call)');
-                    }
-                  }, addTrailingNewline: false);
-                  indent.add(' catch (exception: Error) ');
-                  indent.addScoped('{', '}', () {
-                    indent.writeln('wrapped = wrapError(exception)');
-                    if (method.isAsynchronous) {
-                      indent.writeln('reply.reply(wrapped)');
-                    }
-                  });
-                  if (!method.isAsynchronous) {
+                    });
+                  } else {
+                    indent.write('try ');
+                    indent.addScoped('{', '}', () {
+                      if (method.returnType.isVoid) {
+                        indent.writeln(call);
+                        indent.writeln('wrapped = listOf<Any?>(null)');
+                      } else {
+                        indent.writeln('wrapped = listOf<Any?>($call)');
+                      }
+                    }, addTrailingNewline: false);
+                    indent.add(' catch (exception: Error) ');
+                    indent.addScoped('{', '}', () {
+                      indent.writeln('wrapped = wrapError(exception)');
+                    });
                     indent.writeln('reply.reply(wrapped)');
                   }
                 });
diff --git a/packages/pigeon/lib/swift_generator.dart b/packages/pigeon/lib/swift_generator.dart
index 5d3d15c..0d7a9e8 100644
--- a/packages/pigeon/lib/swift_generator.dart
+++ b/packages/pigeon/lib/swift_generator.dart
@@ -395,13 +395,18 @@
         }).toList();
 
         final String returnType = method.returnType.isVoid
-            ? ''
+            ? 'Void'
             : _nullsafeSwiftTypeForDartType(method.returnType);
+
+        final String escapeType =
+            method.returnType.isVoid ? 'Void' : returnType;
+
         addDocumentationComments(
             indent, method.documentationComments, _docCommentSpec);
 
         if (method.isAsynchronous) {
-          argSignature.add('completion: @escaping ($returnType) -> Void');
+          argSignature.add(
+              'completion: @escaping (Result<$escapeType, Error>) -> Void');
           indent.writeln('func ${components.name}(${argSignature.join(', ')})');
         } else if (method.returnType.isVoid) {
           indent.writeln(
@@ -470,16 +475,25 @@
               final String call =
                   '${tryStatement}api.${components.name}(${methodArgument.join(', ')})';
               if (method.isAsynchronous) {
+                final String resultName =
+                    method.returnType.isVoid ? 'nil' : 'res';
+                final String successVariableInit =
+                    method.returnType.isVoid ? '' : '(let res)';
                 indent.write('$call ');
-                if (method.returnType.isVoid) {
+
+                indent.addScoped('{ result in', '}', () {
+                  indent.write('switch result ');
                   indent.addScoped('{', '}', () {
-                    indent.writeln('reply(wrapResult(nil))');
+                    indent.writeln('case .success$successVariableInit:');
+                    indent.nest(1, () {
+                      indent.writeln('reply(wrapResult($resultName))');
+                    });
+                    indent.writeln('case .failure(let error):');
+                    indent.nest(1, () {
+                      indent.writeln('reply(wrapError(error))');
+                    });
                   });
-                } else {
-                  indent.addScoped('{ result in', '}', () {
-                    indent.writeln('reply(wrapResult(result))');
-                  });
-                }
+                });
               } else {
                 indent.write('do ');
                 indent.addScoped('{', '}', () {
diff --git a/packages/pigeon/mock_handler_tester/test/message.dart b/packages/pigeon/mock_handler_tester/test/message.dart
index c159ef4..46e5050 100644
--- a/packages/pigeon/mock_handler_tester/test/message.dart
+++ b/packages/pigeon/mock_handler_tester/test/message.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
 
diff --git a/packages/pigeon/mock_handler_tester/test/test.dart b/packages/pigeon/mock_handler_tester/test/test.dart
index 83fb22e..19bc70a 100644
--- a/packages/pigeon/mock_handler_tester/test/test.dart
+++ b/packages/pigeon/mock_handler_tester/test/test.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, unnecessary_import
 // ignore_for_file: avoid_relative_lib_imports
diff --git a/packages/pigeon/pigeons/core_tests.dart b/packages/pigeon/pigeons/core_tests.dart
index fe1cb9b..8e13b8d 100644
--- a/packages/pigeon/pigeons/core_tests.dart
+++ b/packages/pigeon/pigeons/core_tests.dart
@@ -200,6 +200,14 @@
   @SwiftFunction('echoAsync(_:)')
   String echoAsyncString(String aString);
 
+  /// Responds with an error from an async function returning a value.
+  @async
+  Object? throwAsyncError();
+
+  /// Responds with an error from an async void function.
+  @async
+  void throwAsyncErrorFromVoid();
+
   // ========== Flutter API test wrappers ==========
 
   @async
diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java
index 8adeaba..8e7ebf8 100644
--- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java
+++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/AlternateLanguageTestPlugin.java
@@ -147,6 +147,16 @@
   }
 
   @Override
+  public void throwAsyncError(Result<Object> result) {
+    result.error(new RuntimeException("An error"));
+  }
+
+  @Override
+  public void throwAsyncErrorFromVoid(Result<Void> result) {
+    result.error(new RuntimeException("An error"));
+  }
+
+  @Override
   public void callFlutterNoop(Result<Void> result) {
     flutterApi.noop(
         new FlutterIntegrationCoreApi.Reply<Void>() {
diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java
index beea981..fa5ce63 100644
--- a/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java
+++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/android/src/main/java/com/example/alternate_language_test_plugin/CoreTests.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 package com.example.alternate_language_test_plugin;
@@ -828,6 +828,10 @@
     void noopAsync(Result<Void> result);
     /** Returns the passed string asynchronously. */
     void echoAsyncString(@NonNull String aString, Result<String> result);
+    /** Responds with an error from an async function returning a value. */
+    void throwAsyncError(Result<Object> result);
+    /** Responds with an error from an async void function. */
+    void throwAsyncErrorFromVoid(Result<Void> result);
 
     void callFlutterNoop(Result<Void> result);
 
@@ -1468,6 +1472,74 @@
         BasicMessageChannel<Object> channel =
             new BasicMessageChannel<>(
                 binaryMessenger,
+                "dev.flutter.pigeon.HostIntegrationCoreApi.throwAsyncError",
+                getCodec());
+        if (api != null) {
+          channel.setMessageHandler(
+              (message, reply) -> {
+                ArrayList<Object> wrapped = new ArrayList<Object>();
+                try {
+                  Result<Object> resultCallback =
+                      new Result<Object>() {
+                        public void success(Object result) {
+                          wrapped.add(0, result);
+                          reply.reply(wrapped);
+                        }
+
+                        public void error(Throwable error) {
+                          ArrayList<Object> wrappedError = wrapError(error);
+                          reply.reply(wrappedError);
+                        }
+                      };
+
+                  api.throwAsyncError(resultCallback);
+                } catch (Error | RuntimeException exception) {
+                  ArrayList<Object> wrappedError = wrapError(exception);
+                  reply.reply(wrappedError);
+                }
+              });
+        } else {
+          channel.setMessageHandler(null);
+        }
+      }
+      {
+        BasicMessageChannel<Object> channel =
+            new BasicMessageChannel<>(
+                binaryMessenger,
+                "dev.flutter.pigeon.HostIntegrationCoreApi.throwAsyncErrorFromVoid",
+                getCodec());
+        if (api != null) {
+          channel.setMessageHandler(
+              (message, reply) -> {
+                ArrayList<Object> wrapped = new ArrayList<Object>();
+                try {
+                  Result<Void> resultCallback =
+                      new Result<Void>() {
+                        public void success(Void result) {
+                          wrapped.add(0, null);
+                          reply.reply(wrapped);
+                        }
+
+                        public void error(Throwable error) {
+                          ArrayList<Object> wrappedError = wrapError(error);
+                          reply.reply(wrappedError);
+                        }
+                      };
+
+                  api.throwAsyncErrorFromVoid(resultCallback);
+                } catch (Error | RuntimeException exception) {
+                  ArrayList<Object> wrappedError = wrapError(exception);
+                  reply.reply(wrappedError);
+                }
+              });
+        } else {
+          channel.setMessageHandler(null);
+        }
+      }
+      {
+        BasicMessageChannel<Object> channel =
+            new BasicMessageChannel<>(
+                binaryMessenger,
                 "dev.flutter.pigeon.HostIntegrationCoreApi.callFlutterNoop",
                 getCodec());
         if (api != null) {
diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/AlternateLanguageTestPlugin.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/AlternateLanguageTestPlugin.m
index 22cfcc1..2f9cb56 100644
--- a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/AlternateLanguageTestPlugin.m
+++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/AlternateLanguageTestPlugin.m
@@ -132,6 +132,14 @@
   completion(aString, nil);
 }
 
+- (void)throwAsyncErrorWithCompletion:(void (^)(id _Nullable, FlutterError *_Nullable))completion {
+  completion(nil, [FlutterError errorWithCode:@"An error" message:nil details:nil]);
+}
+
+- (void)throwAsyncErrorFromVoidWithCompletion:(void (^)(FlutterError *_Nullable))completion {
+  completion([FlutterError errorWithCode:@"An error" message:nil details:nil]);
+}
+
 - (void)callFlutterNoopWithCompletion:(void (^)(FlutterError *_Nullable))completion {
   [self.flutterAPI noopWithCompletion:^(NSError *error) {
     completion(error);
diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h
index 4ab33c4..95a0b31 100644
--- a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h
+++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.h
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 #import <Foundation/Foundation.h>
@@ -181,6 +181,10 @@
 /// Returns the passed string asynchronously.
 - (void)echoAsyncString:(NSString *)aString
              completion:(void (^)(NSString *_Nullable, FlutterError *_Nullable))completion;
+/// Responds with an error from an async function returning a value.
+- (void)throwAsyncErrorWithCompletion:(void (^)(id _Nullable, FlutterError *_Nullable))completion;
+/// Responds with an error from an async void function.
+- (void)throwAsyncErrorFromVoidWithCompletion:(void (^)(FlutterError *_Nullable))completion;
 - (void)callFlutterNoopWithCompletion:(void (^)(FlutterError *_Nullable))completion;
 - (void)callFlutterEchoAllTypes:(AllTypes *)everything
                      completion:(void (^)(AllTypes *_Nullable, FlutterError *_Nullable))completion;
diff --git a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m
index f135dbc..b8384a5 100644
--- a/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m
+++ b/packages/pigeon/platform_tests/alternate_language_test_plugin/ios/Classes/CoreTests.gen.m
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 #import "CoreTests.gen.h"
@@ -733,6 +733,46 @@
       [channel setMessageHandler:nil];
     }
   }
+  /// Responds with an error from an async function returning a value.
+  {
+    FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
+           initWithName:@"dev.flutter.pigeon.HostIntegrationCoreApi.throwAsyncError"
+        binaryMessenger:binaryMessenger
+                  codec:HostIntegrationCoreApiGetCodec()];
+    if (api) {
+      NSCAssert([api respondsToSelector:@selector(throwAsyncErrorWithCompletion:)],
+                @"HostIntegrationCoreApi api (%@) doesn't respond to "
+                @"@selector(throwAsyncErrorWithCompletion:)",
+                api);
+      [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
+        [api throwAsyncErrorWithCompletion:^(id _Nullable output, FlutterError *_Nullable error) {
+          callback(wrapResult(output, error));
+        }];
+      }];
+    } else {
+      [channel setMessageHandler:nil];
+    }
+  }
+  /// Responds with an error from an async void function.
+  {
+    FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
+           initWithName:@"dev.flutter.pigeon.HostIntegrationCoreApi.throwAsyncErrorFromVoid"
+        binaryMessenger:binaryMessenger
+                  codec:HostIntegrationCoreApiGetCodec()];
+    if (api) {
+      NSCAssert([api respondsToSelector:@selector(throwAsyncErrorFromVoidWithCompletion:)],
+                @"HostIntegrationCoreApi api (%@) doesn't respond to "
+                @"@selector(throwAsyncErrorFromVoidWithCompletion:)",
+                api);
+      [channel setMessageHandler:^(id _Nullable message, FlutterReply callback) {
+        [api throwAsyncErrorFromVoidWithCompletion:^(FlutterError *_Nullable error) {
+          callback(wrapResult(nil, error));
+        }];
+      }];
+    } else {
+      [channel setMessageHandler:nil];
+    }
+  }
   {
     FlutterBasicMessageChannel *channel = [[FlutterBasicMessageChannel alloc]
            initWithName:@"dev.flutter.pigeon.HostIntegrationCoreApi.callFlutterNoop"
diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/core_tests.gen.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/core_tests.gen.dart
index 09e6614..cda35f5 100644
--- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/core_tests.gen.dart
+++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/core_tests.gen.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
 
@@ -788,6 +788,51 @@
     }
   }
 
+  /// Responds with an error from an async function returning a value.
+  Future<Object?> throwAsyncError() async {
+    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+        'dev.flutter.pigeon.HostIntegrationCoreApi.throwAsyncError', codec,
+        binaryMessenger: _binaryMessenger);
+    final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
+    if (replyList == null) {
+      throw PlatformException(
+        code: 'channel-error',
+        message: 'Unable to establish connection on channel.',
+      );
+    } else if (replyList.length > 1) {
+      throw PlatformException(
+        code: replyList[0]! as String,
+        message: replyList[1] as String?,
+        details: replyList[2],
+      );
+    } else {
+      return replyList[0];
+    }
+  }
+
+  /// Responds with an error from an async void function.
+  Future<void> throwAsyncErrorFromVoid() async {
+    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+        'dev.flutter.pigeon.HostIntegrationCoreApi.throwAsyncErrorFromVoid',
+        codec,
+        binaryMessenger: _binaryMessenger);
+    final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
+    if (replyList == null) {
+      throw PlatformException(
+        code: 'channel-error',
+        message: 'Unable to establish connection on channel.',
+      );
+    } else if (replyList.length > 1) {
+      throw PlatformException(
+        code: replyList[0]! as String,
+        message: replyList[1] as String?,
+        details: replyList[2],
+      );
+    } else {
+      return;
+    }
+  }
+
   Future<void> callFlutterNoop() async {
     final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
         'dev.flutter.pigeon.HostIntegrationCoreApi.callFlutterNoop', codec,
diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/flutter_unittests.gen.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/flutter_unittests.gen.dart
index 916e6ba..ba05740 100644
--- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/flutter_unittests.gen.dart
+++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/flutter_unittests.gen.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
 
diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/multiple_arity.gen.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/multiple_arity.gen.dart
index fc58a7d..a4dc594 100644
--- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/multiple_arity.gen.dart
+++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/multiple_arity.gen.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
 
diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/non_null_fields.gen.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/non_null_fields.gen.dart
index 9064cfc..2ee9a0c 100644
--- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/non_null_fields.gen.dart
+++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/non_null_fields.gen.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
 
diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_fields.gen.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_fields.gen.dart
index f387231..12b93bd 100644
--- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_fields.gen.dart
+++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/null_fields.gen.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
 
diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/nullable_returns.gen.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/nullable_returns.gen.dart
index 8bcf83a..97d4ae7 100644
--- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/nullable_returns.gen.dart
+++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/nullable_returns.gen.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
 
diff --git a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/primitive.gen.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/primitive.gen.dart
index 8099d23..9650723 100644
--- a/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/primitive.gen.dart
+++ b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/primitive.gen.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
 
diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart
index 78aa5a8..b37c5ac 100644
--- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart
+++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/integration_tests.dart
@@ -488,9 +488,27 @@
       final String echoObject = await api.echoAsyncString(sentObject);
       expect(echoObject, sentObject);
     });
+
+    testWidgets('async errors are returned from non void methods correctly',
+        (WidgetTester _) async {
+      final HostIntegrationCoreApi api = HostIntegrationCoreApi();
+
+      expect(() async {
+        await api.throwAsyncError();
+      }, throwsA(isA<PlatformException>()));
+    });
+
+    testWidgets('async errors are returned from void methods correctly',
+        (WidgetTester _) async {
+      final HostIntegrationCoreApi api = HostIntegrationCoreApi();
+
+      expect(() async {
+        await api.throwAsyncErrorFromVoid();
+      }, throwsA(isA<PlatformException>()));
+    });
   });
 
-  // These tests rely on the ansync Dart->host calls to work correctly, since
+  // These tests rely on the async Dart->host calls to work correctly, since
   // the host->Dart call is wrapped in a driving Dart->host call, so any test
   // added to this group should have coverage of the relevant arguments and
   // return value in the "Host async API tests" group.
diff --git a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart
index 09e6614..cda35f5 100644
--- a/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart
+++ b/packages/pigeon/platform_tests/shared_test_plugin_code/lib/src/generated/core_tests.gen.dart
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 // ignore_for_file: public_member_api_docs, non_constant_identifier_names, avoid_as, unused_import, unnecessary_parenthesis, prefer_null_aware_operators, omit_local_variable_types, unused_shown_name, unnecessary_import
 
@@ -788,6 +788,51 @@
     }
   }
 
+  /// Responds with an error from an async function returning a value.
+  Future<Object?> throwAsyncError() async {
+    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+        'dev.flutter.pigeon.HostIntegrationCoreApi.throwAsyncError', codec,
+        binaryMessenger: _binaryMessenger);
+    final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
+    if (replyList == null) {
+      throw PlatformException(
+        code: 'channel-error',
+        message: 'Unable to establish connection on channel.',
+      );
+    } else if (replyList.length > 1) {
+      throw PlatformException(
+        code: replyList[0]! as String,
+        message: replyList[1] as String?,
+        details: replyList[2],
+      );
+    } else {
+      return replyList[0];
+    }
+  }
+
+  /// Responds with an error from an async void function.
+  Future<void> throwAsyncErrorFromVoid() async {
+    final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
+        'dev.flutter.pigeon.HostIntegrationCoreApi.throwAsyncErrorFromVoid',
+        codec,
+        binaryMessenger: _binaryMessenger);
+    final List<Object?>? replyList = await channel.send(null) as List<Object?>?;
+    if (replyList == null) {
+      throw PlatformException(
+        code: 'channel-error',
+        message: 'Unable to establish connection on channel.',
+      );
+    } else if (replyList.length > 1) {
+      throw PlatformException(
+        code: replyList[0]! as String,
+        message: replyList[1] as String?,
+        details: replyList[2],
+      );
+    } else {
+      return;
+    }
+  }
+
   Future<void> callFlutterNoop() async {
     final BasicMessageChannel<Object?> channel = BasicMessageChannel<Object?>(
         'dev.flutter.pigeon.HostIntegrationCoreApi.callFlutterNoop', codec,
diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt
index 3447e4b..13ccacc 100644
--- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt
+++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/CoreTests.gen.kt
@@ -1,8 +1,8 @@
 // Copyright 2013 The Flutter Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-//
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// 
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 package com.example.test_plugin
@@ -266,26 +266,30 @@
    * A no-op function taking no arguments and returning no value, to sanity
    * test basic asynchronous calling.
    */
-  fun noopAsync(callback: () -> Unit)
+  fun noopAsync(callback: (Result<Unit>) -> Unit)
   /** Returns the passed string asynchronously. */
-  fun echoAsyncString(aString: String, callback: (String) -> Unit)
-  fun callFlutterNoop(callback: () -> Unit)
-  fun callFlutterEchoAllTypes(everything: AllTypes, callback: (AllTypes) -> Unit)
-  fun callFlutterSendMultipleNullableTypes(aNullableBool: Boolean?, aNullableInt: Long?, aNullableString: String?, callback: (AllNullableTypes) -> Unit)
-  fun callFlutterEchoBool(aBool: Boolean, callback: (Boolean) -> Unit)
-  fun callFlutterEchoInt(anInt: Long, callback: (Long) -> Unit)
-  fun callFlutterEchoDouble(aDouble: Double, callback: (Double) -> Unit)
-  fun callFlutterEchoString(aString: String, callback: (String) -> Unit)
-  fun callFlutterEchoUint8List(aList: ByteArray, callback: (ByteArray) -> Unit)
-  fun callFlutterEchoList(aList: List<Any?>, callback: (List<Any?>) -> Unit)
-  fun callFlutterEchoMap(aMap: Map<String?, Any?>, callback: (Map<String?, Any?>) -> Unit)
-  fun callFlutterEchoNullableBool(aBool: Boolean?, callback: (Boolean?) -> Unit)
-  fun callFlutterEchoNullableInt(anInt: Long?, callback: (Long?) -> Unit)
-  fun callFlutterEchoNullableDouble(aDouble: Double?, callback: (Double?) -> Unit)
-  fun callFlutterEchoNullableString(aString: String?, callback: (String?) -> Unit)
-  fun callFlutterEchoNullableUint8List(aList: ByteArray?, callback: (ByteArray?) -> Unit)
-  fun callFlutterEchoNullableList(aList: List<Any?>?, callback: (List<Any?>?) -> Unit)
-  fun callFlutterEchoNullableMap(aMap: Map<String?, Any?>?, callback: (Map<String?, Any?>?) -> Unit)
+  fun echoAsyncString(aString: String, callback: (Result<String>) -> Unit)
+  /** Responds with an error from an async function returning a value. */
+  fun throwAsyncError(callback: (Result<Any?>) -> Unit)
+  /** Responds with an error from an async void function. */
+  fun throwAsyncErrorFromVoid(callback: (Result<Unit>) -> Unit)
+  fun callFlutterNoop(callback: (Result<Unit>) -> Unit)
+  fun callFlutterEchoAllTypes(everything: AllTypes, callback: (Result<AllTypes>) -> Unit)
+  fun callFlutterSendMultipleNullableTypes(aNullableBool: Boolean?, aNullableInt: Long?, aNullableString: String?, callback: (Result<AllNullableTypes>) -> Unit)
+  fun callFlutterEchoBool(aBool: Boolean, callback: (Result<Boolean>) -> Unit)
+  fun callFlutterEchoInt(anInt: Long, callback: (Result<Long>) -> Unit)
+  fun callFlutterEchoDouble(aDouble: Double, callback: (Result<Double>) -> Unit)
+  fun callFlutterEchoString(aString: String, callback: (Result<String>) -> Unit)
+  fun callFlutterEchoUint8List(aList: ByteArray, callback: (Result<ByteArray>) -> Unit)
+  fun callFlutterEchoList(aList: List<Any?>, callback: (Result<List<Any?>>) -> Unit)
+  fun callFlutterEchoMap(aMap: Map<String?, Any?>, callback: (Result<Map<String?, Any?>>) -> Unit)
+  fun callFlutterEchoNullableBool(aBool: Boolean?, callback: (Result<Boolean?>) -> Unit)
+  fun callFlutterEchoNullableInt(anInt: Long?, callback: (Result<Long?>) -> Unit)
+  fun callFlutterEchoNullableDouble(aDouble: Double?, callback: (Result<Double?>) -> Unit)
+  fun callFlutterEchoNullableString(aString: String?, callback: (Result<String?>) -> Unit)
+  fun callFlutterEchoNullableUint8List(aList: ByteArray?, callback: (Result<ByteArray?>) -> Unit)
+  fun callFlutterEchoNullableList(aList: List<Any?>?, callback: (Result<List<Any?>?>) -> Unit)
+  fun callFlutterEchoNullableMap(aMap: Map<String?, Any?>?, callback: (Result<Map<String?, Any?>?>) -> Unit)
 
   companion object {
     /** The codec used by HostIntegrationCoreApi. */
@@ -317,9 +321,9 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val everythingArg = args[0] as AllTypes
             try {
-              val args = message as List<Any?>
-              val everythingArg = args[0] as AllTypes
               wrapped = listOf<Any?>(api.echoAllTypes(everythingArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -335,9 +339,9 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val everythingArg = args[0] as? AllNullableTypes
             try {
-              val args = message as List<Any?>
-              val everythingArg = args[0] as? AllNullableTypes
               wrapped = listOf<Any?>(api.echoAllNullableTypes(everythingArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -370,9 +374,9 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val anIntArg = args[0].let { if (it is Int) it.toLong() else it as Long }
             try {
-              val args = message as List<Any?>
-              val anIntArg = args[0].let { if (it is Int) it.toLong() else it as Long }
               wrapped = listOf<Any?>(api.echoInt(anIntArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -388,9 +392,9 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val aDoubleArg = args[0] as Double
             try {
-              val args = message as List<Any?>
-              val aDoubleArg = args[0] as Double
               wrapped = listOf<Any?>(api.echoDouble(aDoubleArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -406,9 +410,9 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val aBoolArg = args[0] as Boolean
             try {
-              val args = message as List<Any?>
-              val aBoolArg = args[0] as Boolean
               wrapped = listOf<Any?>(api.echoBool(aBoolArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -424,9 +428,9 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val aStringArg = args[0] as String
             try {
-              val args = message as List<Any?>
-              val aStringArg = args[0] as String
               wrapped = listOf<Any?>(api.echoString(aStringArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -442,9 +446,9 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val aUint8ListArg = args[0] as ByteArray
             try {
-              val args = message as List<Any?>
-              val aUint8ListArg = args[0] as ByteArray
               wrapped = listOf<Any?>(api.echoUint8List(aUint8ListArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -460,9 +464,9 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val anObjectArg = args[0] as Any
             try {
-              val args = message as List<Any?>
-              val anObjectArg = args[0] as Any
               wrapped = listOf<Any?>(api.echoObject(anObjectArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -478,9 +482,9 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val wrapperArg = args[0] as AllNullableTypesWrapper
             try {
-              val args = message as List<Any?>
-              val wrapperArg = args[0] as AllNullableTypesWrapper
               wrapped = listOf<Any?>(api.extractNestedNullableString(wrapperArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -496,9 +500,9 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val nullableStringArg = args[0] as? String
             try {
-              val args = message as List<Any?>
-              val nullableStringArg = args[0] as? String
               wrapped = listOf<Any?>(api.createNestedNullableString(nullableStringArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -514,11 +518,11 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val aNullableBoolArg = args[0] as? Boolean
+            val aNullableIntArg = args[1].let { if (it is Int) it.toLong() else it as? Long }
+            val aNullableStringArg = args[2] as? String
             try {
-              val args = message as List<Any?>
-              val aNullableBoolArg = args[0] as? Boolean
-              val aNullableIntArg = args[1].let { if (it is Int) it.toLong() else it as? Long }
-              val aNullableStringArg = args[2] as? String
               wrapped = listOf<Any?>(api.sendMultipleNullableTypes(aNullableBoolArg, aNullableIntArg, aNullableStringArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -534,9 +538,9 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val aNullableIntArg = args[0].let { if (it is Int) it.toLong() else it as? Long }
             try {
-              val args = message as List<Any?>
-              val aNullableIntArg = args[0].let { if (it is Int) it.toLong() else it as? Long }
               wrapped = listOf<Any?>(api.echoNullableInt(aNullableIntArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -552,9 +556,9 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val aNullableDoubleArg = args[0] as? Double
             try {
-              val args = message as List<Any?>
-              val aNullableDoubleArg = args[0] as? Double
               wrapped = listOf<Any?>(api.echoNullableDouble(aNullableDoubleArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -570,9 +574,9 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val aNullableBoolArg = args[0] as? Boolean
             try {
-              val args = message as List<Any?>
-              val aNullableBoolArg = args[0] as? Boolean
               wrapped = listOf<Any?>(api.echoNullableBool(aNullableBoolArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -588,9 +592,9 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val aNullableStringArg = args[0] as? String
             try {
-              val args = message as List<Any?>
-              val aNullableStringArg = args[0] as? String
               wrapped = listOf<Any?>(api.echoNullableString(aNullableStringArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -606,9 +610,9 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val aNullableUint8ListArg = args[0] as? ByteArray
             try {
-              val args = message as List<Any?>
-              val aNullableUint8ListArg = args[0] as? ByteArray
               wrapped = listOf<Any?>(api.echoNullableUint8List(aNullableUint8ListArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -624,9 +628,9 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val aNullableObjectArg = args[0] as? Any
             try {
-              val args = message as List<Any?>
-              val aNullableObjectArg = args[0] as? Any
               wrapped = listOf<Any?>(api.echoNullableObject(aNullableObjectArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -642,13 +646,13 @@
         if (api != null) {
           channel.setMessageHandler { _, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              api.noopAsync() {
+            api.noopAsync() { result: Result<Unit> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
                 reply.reply(wrapResult(null))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
@@ -660,15 +664,53 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              val args = message as List<Any?>
-              val aStringArg = args[0] as String
-              api.echoAsyncString(aStringArg) {
-                reply.reply(wrapResult(it))
+            val args = message as List<Any?>
+            val aStringArg = args[0] as String
+            api.echoAsyncString(aStringArg) { result: Result<String> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
+            }
+          }
+        } else {
+          channel.setMessageHandler(null)
+        }
+      }
+      run {
+        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.HostIntegrationCoreApi.throwAsyncError", codec)
+        if (api != null) {
+          channel.setMessageHandler { _, reply ->
+            var wrapped = listOf<Any?>()
+            api.throwAsyncError() { result: Result<Any?> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
+              }
+            }
+          }
+        } else {
+          channel.setMessageHandler(null)
+        }
+      }
+      run {
+        val channel = BasicMessageChannel<Any?>(binaryMessenger, "dev.flutter.pigeon.HostIntegrationCoreApi.throwAsyncErrorFromVoid", codec)
+        if (api != null) {
+          channel.setMessageHandler { _, reply ->
+            var wrapped = listOf<Any?>()
+            api.throwAsyncErrorFromVoid() { result: Result<Unit> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                reply.reply(wrapResult(null))
+              }
             }
           }
         } else {
@@ -680,13 +722,13 @@
         if (api != null) {
           channel.setMessageHandler { _, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              api.callFlutterNoop() {
+            api.callFlutterNoop() { result: Result<Unit> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
                 reply.reply(wrapResult(null))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
@@ -698,15 +740,16 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              val args = message as List<Any?>
-              val everythingArg = args[0] as AllTypes
-              api.callFlutterEchoAllTypes(everythingArg) {
-                reply.reply(wrapResult(it))
+            val args = message as List<Any?>
+            val everythingArg = args[0] as AllTypes
+            api.callFlutterEchoAllTypes(everythingArg) { result: Result<AllTypes> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
@@ -718,17 +761,18 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              val args = message as List<Any?>
-              val aNullableBoolArg = args[0] as? Boolean
-              val aNullableIntArg = args[1].let { if (it is Int) it.toLong() else it as? Long }
-              val aNullableStringArg = args[2] as? String
-              api.callFlutterSendMultipleNullableTypes(aNullableBoolArg, aNullableIntArg, aNullableStringArg) {
-                reply.reply(wrapResult(it))
+            val args = message as List<Any?>
+            val aNullableBoolArg = args[0] as? Boolean
+            val aNullableIntArg = args[1].let { if (it is Int) it.toLong() else it as? Long }
+            val aNullableStringArg = args[2] as? String
+            api.callFlutterSendMultipleNullableTypes(aNullableBoolArg, aNullableIntArg, aNullableStringArg) { result: Result<AllNullableTypes> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
@@ -740,15 +784,16 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              val args = message as List<Any?>
-              val aBoolArg = args[0] as Boolean
-              api.callFlutterEchoBool(aBoolArg) {
-                reply.reply(wrapResult(it))
+            val args = message as List<Any?>
+            val aBoolArg = args[0] as Boolean
+            api.callFlutterEchoBool(aBoolArg) { result: Result<Boolean> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
@@ -760,15 +805,16 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              val args = message as List<Any?>
-              val anIntArg = args[0].let { if (it is Int) it.toLong() else it as Long }
-              api.callFlutterEchoInt(anIntArg) {
-                reply.reply(wrapResult(it))
+            val args = message as List<Any?>
+            val anIntArg = args[0].let { if (it is Int) it.toLong() else it as Long }
+            api.callFlutterEchoInt(anIntArg) { result: Result<Long> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
@@ -780,15 +826,16 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              val args = message as List<Any?>
-              val aDoubleArg = args[0] as Double
-              api.callFlutterEchoDouble(aDoubleArg) {
-                reply.reply(wrapResult(it))
+            val args = message as List<Any?>
+            val aDoubleArg = args[0] as Double
+            api.callFlutterEchoDouble(aDoubleArg) { result: Result<Double> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
@@ -800,15 +847,16 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              val args = message as List<Any?>
-              val aStringArg = args[0] as String
-              api.callFlutterEchoString(aStringArg) {
-                reply.reply(wrapResult(it))
+            val args = message as List<Any?>
+            val aStringArg = args[0] as String
+            api.callFlutterEchoString(aStringArg) { result: Result<String> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
@@ -820,15 +868,16 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              val args = message as List<Any?>
-              val aListArg = args[0] as ByteArray
-              api.callFlutterEchoUint8List(aListArg) {
-                reply.reply(wrapResult(it))
+            val args = message as List<Any?>
+            val aListArg = args[0] as ByteArray
+            api.callFlutterEchoUint8List(aListArg) { result: Result<ByteArray> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
@@ -840,15 +889,16 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              val args = message as List<Any?>
-              val aListArg = args[0] as List<Any?>
-              api.callFlutterEchoList(aListArg) {
-                reply.reply(wrapResult(it))
+            val args = message as List<Any?>
+            val aListArg = args[0] as List<Any?>
+            api.callFlutterEchoList(aListArg) { result: Result<List<Any?>> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
@@ -860,15 +910,16 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              val args = message as List<Any?>
-              val aMapArg = args[0] as Map<String?, Any?>
-              api.callFlutterEchoMap(aMapArg) {
-                reply.reply(wrapResult(it))
+            val args = message as List<Any?>
+            val aMapArg = args[0] as Map<String?, Any?>
+            api.callFlutterEchoMap(aMapArg) { result: Result<Map<String?, Any?>> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
@@ -880,15 +931,16 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              val args = message as List<Any?>
-              val aBoolArg = args[0] as? Boolean
-              api.callFlutterEchoNullableBool(aBoolArg) {
-                reply.reply(wrapResult(it))
+            val args = message as List<Any?>
+            val aBoolArg = args[0] as? Boolean
+            api.callFlutterEchoNullableBool(aBoolArg) { result: Result<Boolean?> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
@@ -900,15 +952,16 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              val args = message as List<Any?>
-              val anIntArg = args[0].let { if (it is Int) it.toLong() else it as? Long }
-              api.callFlutterEchoNullableInt(anIntArg) {
-                reply.reply(wrapResult(it))
+            val args = message as List<Any?>
+            val anIntArg = args[0].let { if (it is Int) it.toLong() else it as? Long }
+            api.callFlutterEchoNullableInt(anIntArg) { result: Result<Long?> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
@@ -920,15 +973,16 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              val args = message as List<Any?>
-              val aDoubleArg = args[0] as? Double
-              api.callFlutterEchoNullableDouble(aDoubleArg) {
-                reply.reply(wrapResult(it))
+            val args = message as List<Any?>
+            val aDoubleArg = args[0] as? Double
+            api.callFlutterEchoNullableDouble(aDoubleArg) { result: Result<Double?> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
@@ -940,15 +994,16 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              val args = message as List<Any?>
-              val aStringArg = args[0] as? String
-              api.callFlutterEchoNullableString(aStringArg) {
-                reply.reply(wrapResult(it))
+            val args = message as List<Any?>
+            val aStringArg = args[0] as? String
+            api.callFlutterEchoNullableString(aStringArg) { result: Result<String?> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
@@ -960,15 +1015,16 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              val args = message as List<Any?>
-              val aListArg = args[0] as? ByteArray
-              api.callFlutterEchoNullableUint8List(aListArg) {
-                reply.reply(wrapResult(it))
+            val args = message as List<Any?>
+            val aListArg = args[0] as? ByteArray
+            api.callFlutterEchoNullableUint8List(aListArg) { result: Result<ByteArray?> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
@@ -980,15 +1036,16 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              val args = message as List<Any?>
-              val aListArg = args[0] as? List<Any?>
-              api.callFlutterEchoNullableList(aListArg) {
-                reply.reply(wrapResult(it))
+            val args = message as List<Any?>
+            val aListArg = args[0] as? List<Any?>
+            api.callFlutterEchoNullableList(aListArg) { result: Result<List<Any?>?> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
@@ -1000,15 +1057,16 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
-            try {
-              val args = message as List<Any?>
-              val aMapArg = args[0] as? Map<String?, Any?>
-              api.callFlutterEchoNullableMap(aMapArg) {
-                reply.reply(wrapResult(it))
+            val args = message as List<Any?>
+            val aMapArg = args[0] as? Map<String?, Any?>
+            api.callFlutterEchoNullableMap(aMapArg) { result: Result<Map<String?, Any?>?> ->
+              val error = result.exceptionOrNull()
+              if (error != null) {
+                reply.reply(wrapError(error))
+              } else {
+                val data = result.getOrNull()
+                reply.reply(wrapResult(data))
               }
-            } catch (exception: Error) {
-              wrapped = wrapError(exception)
-              reply.reply(wrapped)
             }
           }
         } else {
diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt
index e224d02..d608578 100644
--- a/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt
+++ b/packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt
@@ -10,7 +10,6 @@
 import io.flutter.plugin.common.MethodCall
 import io.flutter.plugin.common.MethodChannel
 import io.flutter.plugin.common.MethodChannel.MethodCallHandler
-import io.flutter.plugin.common.MethodChannel.Result
 
 /**
  * This plugin handles the native side of the integration tests in
@@ -104,87 +103,103 @@
     return aNullableObject
   }
 
-  override fun noopAsync(callback: () -> Unit) {
-    callback()
+  override fun noopAsync(callback: (Result<Unit>) -> Unit) {
+    callback(Result.success(Unit))
   }
 
-  override fun echoAsyncString(aString: String, callback: (String) -> Unit) {
-    callback(aString)
+  override fun echoAsyncString(aString: String, callback: (Result<String>) -> Unit) {
+    callback(Result.success(aString))
   }
 
-  override fun callFlutterNoop(callback: () -> Unit) {
-    flutterApi!!.noop() { callback() }
-  }
-
-  override fun callFlutterEchoAllTypes(everything: AllTypes, callback: (AllTypes) -> Unit) {
-    flutterApi!!.echoAllTypes(everything) { echo -> callback(echo) }
-  }
-
-  override fun callFlutterSendMultipleNullableTypes(
-    aNullableBool: Boolean?,
-    aNullableInt: Long?,
-    aNullableString: String?,
-    callback: (AllNullableTypes) -> Unit
-  ) {
-    flutterApi!!.sendMultipleNullableTypes(aNullableBool, aNullableInt, aNullableString) {
-      echo -> callback(echo)
+  override fun throwAsyncError(callback: (Result<Any?>) -> Unit) {
+    try {
+      throw Exception("except")
+    } catch (e: Exception) {
+      callback(Result.failure(e))
     }
   }
 
-  override fun callFlutterEchoBool(aBool: Boolean, callback: (Boolean) -> Unit) {
-    flutterApi!!.echoBool(aBool) { echo -> callback(echo) }
+  override fun throwAsyncErrorFromVoid(callback: (Result<Unit>) -> Unit) {
+    try {
+      throw Exception("except")
+    } catch (e: Exception) {
+      callback(Result.failure(e))
+    }
   }
 
-  override fun callFlutterEchoInt(anInt: Long, callback: (Long) -> Unit) {
-    flutterApi!!.echoInt(anInt) { echo -> callback(echo) }
+  override fun callFlutterNoop(callback: (Result<Unit>) -> Unit) {
+    flutterApi!!.noop() { callback(Result.success(Unit)) }
   }
 
-  override fun callFlutterEchoDouble(aDouble: Double, callback: (Double) -> Unit) {
-    flutterApi!!.echoDouble(aDouble) { echo -> callback(echo) }
+  override fun callFlutterEchoAllTypes(everything: AllTypes, callback: (Result<AllTypes>) -> Unit) {
+    flutterApi!!.echoAllTypes(everything) { echo -> callback(Result.success(echo)) }
   }
 
-  override fun callFlutterEchoString(aString: String, callback: (String) -> Unit) {
-    flutterApi!!.echoString(aString) { echo -> callback(echo) }
+  override fun callFlutterSendMultipleNullableTypes(
+    aNullableBool: Boolean?, 
+    aNullableInt: Long?, 
+    aNullableString: String?, 
+    callback: (Result<AllNullableTypes>) -> Unit
+  ) {
+    flutterApi!!.sendMultipleNullableTypes(aNullableBool, aNullableInt, aNullableString) {
+      echo -> callback(Result.success(echo))
+    }
   }
 
-  override fun callFlutterEchoUint8List(aList: ByteArray, callback: (ByteArray) -> Unit) {
-    flutterApi!!.echoUint8List(aList) { echo -> callback(echo) }
+  override fun callFlutterEchoBool(aBool: Boolean, callback: (Result<Boolean>) -> Unit) {
+    flutterApi!!.echoBool(aBool) { echo -> callback(Result.success(echo)) }
   }
 
-  override fun callFlutterEchoList(aList: List<Any?>, callback: (List<Any?>) -> Unit) {
-    flutterApi!!.echoList(aList) { echo -> callback(echo) }
+  override fun callFlutterEchoInt(anInt: Long, callback: (Result<Long>) -> Unit) {
+    flutterApi!!.echoInt(anInt) { echo -> callback(Result.success(echo)) }
   }
 
-  override fun callFlutterEchoMap(aMap: Map<String?, Any?>, callback: (Map<String?, Any?>) -> Unit) {
-    flutterApi!!.echoMap(aMap) { echo -> callback(echo) }
+  override fun callFlutterEchoDouble(aDouble: Double, callback: (Result<Double>) -> Unit) {
+    flutterApi!!.echoDouble(aDouble) { echo -> callback(Result.success(echo)) }
   }
 
-  override fun callFlutterEchoNullableBool(aBool: Boolean?, callback: (Boolean?) -> Unit) {
-    flutterApi!!.echoNullableBool(aBool) { echo -> callback(echo) }
+  override fun callFlutterEchoString(aString: String, callback: (Result<String>) -> Unit) {
+    flutterApi!!.echoString(aString) { echo -> callback(Result.success(echo)) }
   }
 
-  override fun callFlutterEchoNullableInt(anInt: Long?, callback: (Long?) -> Unit) {
-    flutterApi!!.echoNullableInt(anInt) { echo -> callback(echo) }
+  override fun callFlutterEchoUint8List(aList: ByteArray, callback: (Result<ByteArray>) -> Unit) {
+    flutterApi!!.echoUint8List(aList) { echo -> callback(Result.success(echo)) }
   }
 
-  override fun callFlutterEchoNullableDouble(aDouble: Double?, callback: (Double?) -> Unit) {
-    flutterApi!!.echoNullableDouble(aDouble) { echo -> callback(echo) }
+  override fun callFlutterEchoList(aList: List<Any?>, callback: (Result<List<Any?>>) -> Unit){
+    flutterApi!!.echoList(aList) { echo -> callback(Result.success(echo)) }
   }
 
-  override fun callFlutterEchoNullableString(aString: String?, callback: (String?) -> Unit) {
-    flutterApi!!.echoNullableString(aString) { echo -> callback(echo) }
+  override fun callFlutterEchoMap(aMap: Map<String?, Any?>, callback: (Result<Map<String?, Any?>>) -> Unit) {
+    flutterApi!!.echoMap(aMap) { echo -> callback(Result.success(echo)) }
   }
 
-  override fun callFlutterEchoNullableUint8List(aList: ByteArray?, callback: (ByteArray?) -> Unit) {
-    flutterApi!!.echoNullableUint8List(aList) { echo -> callback(echo) }
+  override fun callFlutterEchoNullableBool(aBool: Boolean?, callback: (Result<Boolean?>) -> Unit) {
+    flutterApi!!.echoNullableBool(aBool) { echo -> callback(Result.success(echo)) }
   }
 
-  override fun callFlutterEchoNullableList(aList: List<Any?>?, callback: (List<Any?>?) -> Unit) {
-    flutterApi!!.echoNullableList(aList) { echo -> callback(echo) }
+  override fun callFlutterEchoNullableInt(anInt: Long?, callback: (Result<Long?>) -> Unit) {
+    flutterApi!!.echoNullableInt(anInt) { echo -> callback(Result.success(echo)) }
   }
 
-  override fun callFlutterEchoNullableMap(aMap: Map<String?, Any?>?, callback: (Map<String?, Any?>?) -> Unit) {
-    flutterApi!!.echoNullableMap(aMap) { echo -> callback(echo) }
+  override fun callFlutterEchoNullableDouble(aDouble: Double?, callback: (Result<Double?>) -> Unit) {
+    flutterApi!!.echoNullableDouble(aDouble) { echo -> callback(Result.success(echo)) }
+  }
+
+  override fun callFlutterEchoNullableString(aString: String?, callback: (Result<String?>) -> Unit) {
+    flutterApi!!.echoNullableString(aString) { echo -> callback(Result.success(echo)) }
+  }
+
+  override fun callFlutterEchoNullableUint8List(aList: ByteArray?, callback: (Result<ByteArray?>) -> Unit) {
+    flutterApi!!.echoNullableUint8List(aList) { echo -> callback(Result.success(echo)) }
+  }
+
+  override fun callFlutterEchoNullableList(aList: List<Any?>?, callback: (Result<List<Any?>?>) -> Unit) {
+    flutterApi!!.echoNullableList(aList) { echo -> callback(Result.success(echo)) }
+  }
+
+  override fun callFlutterEchoNullableMap(aMap: Map<String?, Any?>?, callback: (Result<Map<String?, Any?>?>) -> Unit) {
+    flutterApi!!.echoNullableMap(aMap) { echo -> callback(Result.success(echo)) }
   }
 
 }
diff --git a/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AsyncHandlersTest.kt b/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AsyncHandlersTest.kt
index 668e3d7..7deea92 100644
--- a/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AsyncHandlersTest.kt
+++ b/packages/pigeon/platform_tests/test_plugin/android/src/test/kotlin/com/example/test_plugin/AsyncHandlersTest.kt
@@ -58,8 +58,8 @@
         every { binaryMessenger.setMessageHandler("dev.flutter.pigeon.Api2Host.voidVoid", any()) } returns Unit
         every { binaryMessenger.setMessageHandler(channelName, capture(handlerSlot)) } returns Unit
         every { api.calculate(any(), any()) } answers {
-            val callback = arg<(Value) -> Unit>(1)
-            callback(output)
+            val callback = arg<(Result<Value>) -> Unit>(1)
+            callback(Result.success(output))
         }
 
         Api2Host.setUp(binaryMessenger, api)
@@ -68,6 +68,7 @@
         val message = codec.encodeMessage(listOf(input))
         message?.rewind()
         handlerSlot.captured.onMessage(message) {
+            assertNotNull(it)
             it?.rewind()
             @Suppress("UNCHECKED_CAST")
             val wrapped = codec.decodeMessage(it) as MutableList<Any>?
diff --git a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AsyncHandlersTest.swift b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AsyncHandlersTest.swift
index a5a4ae7..b9f5691 100644
--- a/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AsyncHandlersTest.swift
+++ b/packages/pigeon/platform_tests/test_plugin/example/ios/RunnerTests/AsyncHandlersTest.swift
@@ -7,12 +7,12 @@
 class MockApi2Host: Api2Host {
   var output: Int32?
 
-  func calculate(value: Value, completion: @escaping (Value) -> Void) {
-    completion(Value(number: output))
+  func calculate(value: Value, completion: @escaping (Result<Value, Error>) -> Void) {
+      completion(.success(Value(number: output)))
   }
 
-  func voidVoid(completion: @escaping () -> Void) {
-    completion()
+  func voidVoid(completion: @escaping (Result<Void, Error>) -> Void) {
+    completion(.success(()))
   }
 }
 
diff --git a/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift
index 0026c39..c825b7c 100644
--- a/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift
+++ b/packages/pigeon/platform_tests/test_plugin/ios/Classes/CoreTests.gen.swift
@@ -1,8 +1,8 @@
 // Copyright 2013 The Flutter Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-//
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// 
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 import Foundation
@@ -117,23 +117,23 @@
   var aNullableString: String? = nil
 
   static func fromList(_ list: [Any?]) -> AllNullableTypes? {
-    let aNullableBool = list[0] as? Bool
-    let aNullableInt = list[1] as? Int32
-    let aNullableDouble = list[2] as? Double
-    let aNullableByteArray = list[3] as? FlutterStandardTypedData
-    let aNullable4ByteArray = list[4] as? FlutterStandardTypedData
-    let aNullable8ByteArray = list[5] as? FlutterStandardTypedData
-    let aNullableFloatArray = list[6] as? FlutterStandardTypedData
-    let aNullableList = list[7] as? [Any?]
-    let aNullableMap = list[8] as? [AnyHashable: Any?]
-    let nullableNestedList = list[9] as? [[Bool?]?]
-    let nullableMapWithAnnotations = list[10] as? [String?: String?]
-    let nullableMapWithObject = list[11] as? [String?: Any?]
+    let aNullableBool = list[0] as? Bool 
+    let aNullableInt = list[1] as? Int32 
+    let aNullableDouble = list[2] as? Double 
+    let aNullableByteArray = list[3] as? FlutterStandardTypedData 
+    let aNullable4ByteArray = list[4] as? FlutterStandardTypedData 
+    let aNullable8ByteArray = list[5] as? FlutterStandardTypedData 
+    let aNullableFloatArray = list[6] as? FlutterStandardTypedData 
+    let aNullableList = list[7] as? [Any?] 
+    let aNullableMap = list[8] as? [AnyHashable: Any?] 
+    let nullableNestedList = list[9] as? [[Bool?]?] 
+    let nullableMapWithAnnotations = list[10] as? [String?: String?] 
+    let nullableMapWithObject = list[11] as? [String?: Any?] 
     var aNullableEnum: AnEnum? = nil
     if let aNullableEnumRawValue = list[12] as? Int {
       aNullableEnum = AnEnum(rawValue: aNullableEnumRawValue)
     }
-    let aNullableString = list[13] as? String
+    let aNullableString = list[13] as? String 
 
     return AllNullableTypes(
       aNullableBool: aNullableBool,
@@ -284,26 +284,30 @@
   func echo(_ aNullableObject: Any?) throws -> Any?
   /// A no-op function taking no arguments and returning no value, to sanity
   /// test basic asynchronous calling.
-  func noopAsync(completion: @escaping () -> Void)
+  func noopAsync(completion: @escaping (Result<Void, Error>) -> Void)
   /// Returns the passed string asynchronously.
-  func echoAsync(_ aString: String, completion: @escaping (String) -> Void)
-  func callFlutterNoop(completion: @escaping () -> Void)
-  func callFlutterEcho(_ everything: AllTypes, completion: @escaping (AllTypes) -> Void)
-  func callFlutterSendMultipleNullableTypes(aBool aNullableBool: Bool?, anInt aNullableInt: Int32?, aString aNullableString: String?, completion: @escaping (AllNullableTypes) -> Void)
-  func callFlutterEcho(_ aBool: Bool, completion: @escaping (Bool) -> Void)
-  func callFlutterEcho(_ anInt: Int32, completion: @escaping (Int32) -> Void)
-  func callFlutterEcho(_ aDouble: Double, completion: @escaping (Double) -> Void)
-  func callFlutterEcho(_ aString: String, completion: @escaping (String) -> Void)
-  func callFlutterEcho(_ aList: FlutterStandardTypedData, completion: @escaping (FlutterStandardTypedData) -> Void)
-  func callFlutterEcho(_ aList: [Any?], completion: @escaping ([Any?]) -> Void)
-  func callFlutterEcho(_ aMap: [String?: Any?], completion: @escaping ([String?: Any?]) -> Void)
-  func callFlutterEchoNullable(_ aBool: Bool?, completion: @escaping (Bool?) -> Void)
-  func callFlutterEchoNullable(_ anInt: Int32?, completion: @escaping (Int32?) -> Void)
-  func callFlutterEchoNullable(_ aDouble: Double?, completion: @escaping (Double?) -> Void)
-  func callFlutterEchoNullable(_ aString: String?, completion: @escaping (String?) -> Void)
-  func callFlutterEchoNullable(_ aList: FlutterStandardTypedData?, completion: @escaping (FlutterStandardTypedData?) -> Void)
-  func callFlutterEchoNullable(_ aList: [Any?]?, completion: @escaping ([Any?]?) -> Void)
-  func callFlutterEchoNullable(_ aMap: [String?: Any?]?, completion: @escaping ([String?: Any?]?) -> Void)
+  func echoAsync(_ aString: String, completion: @escaping (Result<String, Error>) -> Void)
+  /// Responds with an error from an async function returning a value.
+  func throwAsyncError(completion: @escaping (Result<Any?, Error>) -> Void)
+  /// Responds with an error from an async void function.
+  func throwAsyncErrorFromVoid(completion: @escaping (Result<Void, Error>) -> Void)
+  func callFlutterNoop(completion: @escaping (Result<Void, Error>) -> Void)
+  func callFlutterEcho(_ everything: AllTypes, completion: @escaping (Result<AllTypes, Error>) -> Void)
+  func callFlutterSendMultipleNullableTypes(aBool aNullableBool: Bool?, anInt aNullableInt: Int32?, aString aNullableString: String?, completion: @escaping (Result<AllNullableTypes, Error>) -> Void)
+  func callFlutterEcho(_ aBool: Bool, completion: @escaping (Result<Bool, Error>) -> Void)
+  func callFlutterEcho(_ anInt: Int32, completion: @escaping (Result<Int32, Error>) -> Void)
+  func callFlutterEcho(_ aDouble: Double, completion: @escaping (Result<Double, Error>) -> Void)
+  func callFlutterEcho(_ aString: String, completion: @escaping (Result<String, Error>) -> Void)
+  func callFlutterEcho(_ aList: FlutterStandardTypedData, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void)
+  func callFlutterEcho(_ aList: [Any?], completion: @escaping (Result<[Any?], Error>) -> Void)
+  func callFlutterEcho(_ aMap: [String?: Any?], completion: @escaping (Result<[String?: Any?], Error>) -> Void)
+  func callFlutterEchoNullable(_ aBool: Bool?, completion: @escaping (Result<Bool?, Error>) -> Void)
+  func callFlutterEchoNullable(_ anInt: Int32?, completion: @escaping (Result<Int32?, Error>) -> Void)
+  func callFlutterEchoNullable(_ aDouble: Double?, completion: @escaping (Result<Double?, Error>) -> Void)
+  func callFlutterEchoNullable(_ aString: String?, completion: @escaping (Result<String?, Error>) -> Void)
+  func callFlutterEchoNullable(_ aList: FlutterStandardTypedData?, completion: @escaping (Result<FlutterStandardTypedData?, Error>) -> Void)
+  func callFlutterEchoNullable(_ aList: [Any?]?, completion: @escaping (Result<[Any?]?, Error>) -> Void)
+  func callFlutterEchoNullable(_ aMap: [String?: Any?]?, completion: @escaping (Result<[String?: Any?]?, Error>) -> Void)
 }
 
 /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
@@ -622,8 +626,13 @@
     let noopAsyncChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostIntegrationCoreApi.noopAsync", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       noopAsyncChannel.setMessageHandler { _, reply in
-        api.noopAsync() {
-          reply(wrapResult(nil))
+        api.noopAsync() { result in
+          switch result {
+            case .success:
+              reply(wrapResult(nil))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -636,17 +645,59 @@
         let args = message as! [Any?]
         let aStringArg = args[0] as! String
         api.echoAsync(aStringArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
       echoAsyncStringChannel.setMessageHandler(nil)
     }
+    /// Responds with an error from an async function returning a value.
+    let throwAsyncErrorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostIntegrationCoreApi.throwAsyncError", binaryMessenger: binaryMessenger, codec: codec)
+    if let api = api {
+      throwAsyncErrorChannel.setMessageHandler { _, reply in
+        api.throwAsyncError() { result in
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
+        }
+      }
+    } else {
+      throwAsyncErrorChannel.setMessageHandler(nil)
+    }
+    /// Responds with an error from an async void function.
+    let throwAsyncErrorFromVoidChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostIntegrationCoreApi.throwAsyncErrorFromVoid", binaryMessenger: binaryMessenger, codec: codec)
+    if let api = api {
+      throwAsyncErrorFromVoidChannel.setMessageHandler { _, reply in
+        api.throwAsyncErrorFromVoid() { result in
+          switch result {
+            case .success:
+              reply(wrapResult(nil))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
+        }
+      }
+    } else {
+      throwAsyncErrorFromVoidChannel.setMessageHandler(nil)
+    }
     let callFlutterNoopChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostIntegrationCoreApi.callFlutterNoop", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       callFlutterNoopChannel.setMessageHandler { _, reply in
-        api.callFlutterNoop() {
-          reply(wrapResult(nil))
+        api.callFlutterNoop() { result in
+          switch result {
+            case .success:
+              reply(wrapResult(nil))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -658,7 +709,12 @@
         let args = message as! [Any?]
         let everythingArg = args[0] as! AllTypes
         api.callFlutterEcho(everythingArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -672,7 +728,12 @@
         let aNullableIntArg = args[1] as? Int32
         let aNullableStringArg = args[2] as? String
         api.callFlutterSendMultipleNullableTypes(aBool: aNullableBoolArg, anInt: aNullableIntArg, aString: aNullableStringArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -684,7 +745,12 @@
         let args = message as! [Any?]
         let aBoolArg = args[0] as! Bool
         api.callFlutterEcho(aBoolArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -696,7 +762,12 @@
         let args = message as! [Any?]
         let anIntArg = args[0] as! Int32
         api.callFlutterEcho(anIntArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -708,7 +779,12 @@
         let args = message as! [Any?]
         let aDoubleArg = args[0] as! Double
         api.callFlutterEcho(aDoubleArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -720,7 +796,12 @@
         let args = message as! [Any?]
         let aStringArg = args[0] as! String
         api.callFlutterEcho(aStringArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -732,7 +813,12 @@
         let args = message as! [Any?]
         let aListArg = args[0] as! FlutterStandardTypedData
         api.callFlutterEcho(aListArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -744,7 +830,12 @@
         let args = message as! [Any?]
         let aListArg = args[0] as! [Any?]
         api.callFlutterEcho(aListArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -756,7 +847,12 @@
         let args = message as! [Any?]
         let aMapArg = args[0] as! [String?: Any?]
         api.callFlutterEcho(aMapArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -768,7 +864,12 @@
         let args = message as! [Any?]
         let aBoolArg = args[0] as? Bool
         api.callFlutterEchoNullable(aBoolArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -780,7 +881,12 @@
         let args = message as! [Any?]
         let anIntArg = args[0] as? Int32
         api.callFlutterEchoNullable(anIntArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -792,7 +898,12 @@
         let args = message as! [Any?]
         let aDoubleArg = args[0] as? Double
         api.callFlutterEchoNullable(aDoubleArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -804,7 +915,12 @@
         let args = message as! [Any?]
         let aStringArg = args[0] as? String
         api.callFlutterEchoNullable(aStringArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -816,7 +932,12 @@
         let args = message as! [Any?]
         let aListArg = args[0] as? FlutterStandardTypedData
         api.callFlutterEchoNullable(aListArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -828,7 +949,12 @@
         let args = message as! [Any?]
         let aListArg = args[0] as? [Any?]
         api.callFlutterEchoNullable(aListArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -840,7 +966,12 @@
         let args = message as! [Any?]
         let aMapArg = args[0] as? [String?: Any?]
         api.callFlutterEchoNullable(aMapArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
diff --git a/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift b/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift
index cd3a07f..5e2260b 100644
--- a/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift
+++ b/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift
@@ -5,6 +5,8 @@
 import Flutter
 import UIKit
 
+extension FlutterError: Error {}
+
 /**
  * This plugin handles the native side of the integration tests in
  * example/integration_test/.
@@ -36,7 +38,7 @@
   }
 
   func throwError() throws {
-    throw ErrType.thrownErrow
+    throw FlutterError(code: "code", message: "message", details: "details")
   }
 
   func echo(_ anInt: Int32) -> Int32 {
@@ -100,96 +102,164 @@
     return aNullableObject
   }
 
-  func noopAsync(completion: @escaping () -> Void) {
-    completion()
+  func noopAsync(completion: @escaping (Result<Void, Error>) -> Void) {
+    completion(.success(Void()))
   }
 
-  func echoAsync(_ aString: String, completion: @escaping (String) -> Void) {
-    completion(aString)
+  func echoAsync(_ aString: String, completion: @escaping (Result<String, Error>) -> Void) {
+    let result: Result<String, Error>
+    result = .success(aString)
+    completion(result)
   }
 
-  func callFlutterNoop(completion: @escaping () -> Void) {
+  func throwAsyncError(completion: @escaping (Result<Any?, Error>) -> Void) {
+    completion(.failure(FlutterError(code: "code", message: "message", details: "details")))
+  }
+
+  func throwAsyncErrorFromVoid(completion: @escaping (Result<Void, Error>) -> Void) {
+    completion(.failure(FlutterError(code: "code", message: "message", details: "details")))
+  }
+
+  func callFlutterNoop(completion: @escaping (Result<Void, Error>) -> Void) {
     flutterAPI.noop() {
-      completion()
+      completion(.success(Void()))
     }
   }
 
-  func callFlutterEcho(_ everything: AllTypes, completion: @escaping (AllTypes) -> Void) {
-      flutterAPI.echo(everything) { completion($0) }
+  func callFlutterEcho(_ everything: AllTypes, completion: @escaping (Result<AllTypes, Error>) -> Void) {
+    flutterAPI.echo(everything) { 
+      let result: Result<AllTypes, Error>
+      result = .success($0)
+      completion(result) 
+    }
   }
 
   func callFlutterSendMultipleNullableTypes(
     aBool aNullableBool: Bool?,
     anInt aNullableInt: Int32?,
     aString aNullableString: String?,
-    completion: @escaping (AllNullableTypes) -> Void
+    completion: @escaping (Result<AllNullableTypes, Error>) -> Void
   ) {
     flutterAPI.sendMultipleNullableTypes(
       aBool: aNullableBool,
       anInt: aNullableInt,
       aString: aNullableString
     ) {
-      completion($0)
+      let result: Result<AllNullableTypes, Error>
+      result = .success($0)
+      completion(result)
     }
   }
 
-  func callFlutterEcho(_ aBool: Bool, completion: @escaping (Bool) -> Void) {
-    flutterAPI.echo(aBool) { completion($0) }
+  func callFlutterEcho(_ aBool: Bool, completion: @escaping (Result<Bool, Error>) -> Void) {
+    flutterAPI.echo(aBool) { 
+      let result: Result<Bool, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEcho(_ anInt: Int32, completion: @escaping (Int32) -> Void) {
-    flutterAPI.echo(anInt) { completion($0) }
+  func callFlutterEcho(_ anInt: Int32, completion: @escaping (Result<Int32, Error>) -> Void) {
+    flutterAPI.echo(anInt) { 
+      let result: Result<Int32, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEcho(_ aDouble: Double, completion: @escaping (Double) -> Void) {
-    flutterAPI.echo(aDouble) { completion($0) }
+  func callFlutterEcho(_ aDouble: Double, completion: @escaping (Result<Double, Error>) -> Void) {
+    flutterAPI.echo(aDouble) { 
+      let result: Result<Double, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEcho(_ aString: String, completion: @escaping (String) -> Void) {
-    flutterAPI.echo(aString) { completion($0) }
+  func callFlutterEcho(_ aString: String, completion: @escaping (Result<String, Error>) -> Void) {
+    flutterAPI.echo(aString) { 
+      let result: Result<String, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEcho(_ aList: FlutterStandardTypedData, completion: @escaping (FlutterStandardTypedData) -> Void) {
-    flutterAPI.echo(aList) { completion($0) }
+  func callFlutterEcho(_ aList: FlutterStandardTypedData, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) {
+    flutterAPI.echo(aList) { 
+      let result: Result<FlutterStandardTypedData, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEcho(_ aList: [Any?], completion: @escaping ([Any?]) -> Void) {
-    flutterAPI.echo(aList) { completion($0) }
+  func callFlutterEcho(_ aList: [Any?], completion: @escaping (Result<[Any?], Error>) -> Void) {
+    flutterAPI.echo(aList) { 
+      let result: Result<[Any?], Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEcho(_ aMap: [String? : Any?], completion: @escaping ([String? : Any?]) -> Void) {
-    flutterAPI.echo(aMap) { completion($0) }
+  func callFlutterEcho(_ aMap: [String? : Any?], completion: @escaping (Result<[String? : Any?], Error>) -> Void) {
+    flutterAPI.echo(aMap) { 
+      let result: Result<[String? : Any?], Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEchoNullable(_ aBool: Bool?, completion: @escaping (Bool?) -> Void) {
-    flutterAPI.echoNullable(aBool) { completion($0) }
+  func callFlutterEchoNullable(_ aBool: Bool?, completion: @escaping (Result<Bool?, Error>) -> Void) {
+    flutterAPI.echoNullable(aBool) { 
+      let result: Result<Bool?, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEchoNullable(_ anInt: Int32?, completion: @escaping (Int32?) -> Void) {
-    flutterAPI.echoNullable(anInt) { completion($0) }
+  func callFlutterEchoNullable(_ anInt: Int32?, completion: @escaping (Result<Int32?, Error>) -> Void) {
+    flutterAPI.echoNullable(anInt) { 
+      let result: Result<Int32?, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEchoNullable(_ aDouble: Double?, completion: @escaping (Double?) -> Void) {
-    flutterAPI.echoNullable(aDouble) { completion($0) }
+  func callFlutterEchoNullable(_ aDouble: Double?, completion: @escaping (Result<Double?, Error>) -> Void) {
+    flutterAPI.echoNullable(aDouble) { 
+      let result: Result<Double?, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEchoNullable(_ aString: String?, completion: @escaping (String?) -> Void) {
-    flutterAPI.echoNullable(aString) { completion($0) }
+  func callFlutterEchoNullable(_ aString: String?, completion: @escaping (Result<String?, Error>) -> Void) {
+    flutterAPI.echoNullable(aString) { 
+      let result: Result<String?, Error>
+      result = .success($0)
+      completion(result)
+    }
+  }
+  
+  func callFlutterEchoNullable(_ aList: FlutterStandardTypedData?, completion: @escaping (Result<FlutterStandardTypedData?, Error>) -> Void) {
+    flutterAPI.echoNullable(aList) {
+      let result: Result<FlutterStandardTypedData?, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEchoNullable(_ aList: FlutterStandardTypedData?, completion: @escaping (FlutterStandardTypedData?) -> Void) {
-    flutterAPI.echoNullable(aList) { completion($0) }
+  func callFlutterEchoNullable(_ aList: [Any?]?, completion: @escaping (Result<[Any?]?, Error>) -> Void) {
+    flutterAPI.echoNullable(aList) {
+      let result: Result<[Any?]?, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEchoNullable(_ aList: [Any?]?, completion: @escaping ([Any?]?) -> Void) {
-    flutterAPI.echoNullable(aList) { completion($0) }
+  func callFlutterEchoNullable(_ aMap: [String? : Any?]?, completion: @escaping (Result<[String? : Any?]?, Error>) -> Void) {
+    flutterAPI.echoNullable(aMap) {
+      let result: Result<[String? : Any?]?, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
-
-  func callFlutterEchoNullable(_ aMap: [String? : Any?]?, completion: @escaping ([String? : Any?]?) -> Void) {
-    flutterAPI.echoNullable(aMap) { completion($0) }
-  }
-}
-
-enum ErrType: Error {
-  case thrownErrow
 }
\ No newline at end of file
diff --git a/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift b/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift
index 0026c39..c825b7c 100644
--- a/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift
+++ b/packages/pigeon/platform_tests/test_plugin/macos/Classes/CoreTests.gen.swift
@@ -1,8 +1,8 @@
 // Copyright 2013 The Flutter Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-//
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// 
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 import Foundation
@@ -117,23 +117,23 @@
   var aNullableString: String? = nil
 
   static func fromList(_ list: [Any?]) -> AllNullableTypes? {
-    let aNullableBool = list[0] as? Bool
-    let aNullableInt = list[1] as? Int32
-    let aNullableDouble = list[2] as? Double
-    let aNullableByteArray = list[3] as? FlutterStandardTypedData
-    let aNullable4ByteArray = list[4] as? FlutterStandardTypedData
-    let aNullable8ByteArray = list[5] as? FlutterStandardTypedData
-    let aNullableFloatArray = list[6] as? FlutterStandardTypedData
-    let aNullableList = list[7] as? [Any?]
-    let aNullableMap = list[8] as? [AnyHashable: Any?]
-    let nullableNestedList = list[9] as? [[Bool?]?]
-    let nullableMapWithAnnotations = list[10] as? [String?: String?]
-    let nullableMapWithObject = list[11] as? [String?: Any?]
+    let aNullableBool = list[0] as? Bool 
+    let aNullableInt = list[1] as? Int32 
+    let aNullableDouble = list[2] as? Double 
+    let aNullableByteArray = list[3] as? FlutterStandardTypedData 
+    let aNullable4ByteArray = list[4] as? FlutterStandardTypedData 
+    let aNullable8ByteArray = list[5] as? FlutterStandardTypedData 
+    let aNullableFloatArray = list[6] as? FlutterStandardTypedData 
+    let aNullableList = list[7] as? [Any?] 
+    let aNullableMap = list[8] as? [AnyHashable: Any?] 
+    let nullableNestedList = list[9] as? [[Bool?]?] 
+    let nullableMapWithAnnotations = list[10] as? [String?: String?] 
+    let nullableMapWithObject = list[11] as? [String?: Any?] 
     var aNullableEnum: AnEnum? = nil
     if let aNullableEnumRawValue = list[12] as? Int {
       aNullableEnum = AnEnum(rawValue: aNullableEnumRawValue)
     }
-    let aNullableString = list[13] as? String
+    let aNullableString = list[13] as? String 
 
     return AllNullableTypes(
       aNullableBool: aNullableBool,
@@ -284,26 +284,30 @@
   func echo(_ aNullableObject: Any?) throws -> Any?
   /// A no-op function taking no arguments and returning no value, to sanity
   /// test basic asynchronous calling.
-  func noopAsync(completion: @escaping () -> Void)
+  func noopAsync(completion: @escaping (Result<Void, Error>) -> Void)
   /// Returns the passed string asynchronously.
-  func echoAsync(_ aString: String, completion: @escaping (String) -> Void)
-  func callFlutterNoop(completion: @escaping () -> Void)
-  func callFlutterEcho(_ everything: AllTypes, completion: @escaping (AllTypes) -> Void)
-  func callFlutterSendMultipleNullableTypes(aBool aNullableBool: Bool?, anInt aNullableInt: Int32?, aString aNullableString: String?, completion: @escaping (AllNullableTypes) -> Void)
-  func callFlutterEcho(_ aBool: Bool, completion: @escaping (Bool) -> Void)
-  func callFlutterEcho(_ anInt: Int32, completion: @escaping (Int32) -> Void)
-  func callFlutterEcho(_ aDouble: Double, completion: @escaping (Double) -> Void)
-  func callFlutterEcho(_ aString: String, completion: @escaping (String) -> Void)
-  func callFlutterEcho(_ aList: FlutterStandardTypedData, completion: @escaping (FlutterStandardTypedData) -> Void)
-  func callFlutterEcho(_ aList: [Any?], completion: @escaping ([Any?]) -> Void)
-  func callFlutterEcho(_ aMap: [String?: Any?], completion: @escaping ([String?: Any?]) -> Void)
-  func callFlutterEchoNullable(_ aBool: Bool?, completion: @escaping (Bool?) -> Void)
-  func callFlutterEchoNullable(_ anInt: Int32?, completion: @escaping (Int32?) -> Void)
-  func callFlutterEchoNullable(_ aDouble: Double?, completion: @escaping (Double?) -> Void)
-  func callFlutterEchoNullable(_ aString: String?, completion: @escaping (String?) -> Void)
-  func callFlutterEchoNullable(_ aList: FlutterStandardTypedData?, completion: @escaping (FlutterStandardTypedData?) -> Void)
-  func callFlutterEchoNullable(_ aList: [Any?]?, completion: @escaping ([Any?]?) -> Void)
-  func callFlutterEchoNullable(_ aMap: [String?: Any?]?, completion: @escaping ([String?: Any?]?) -> Void)
+  func echoAsync(_ aString: String, completion: @escaping (Result<String, Error>) -> Void)
+  /// Responds with an error from an async function returning a value.
+  func throwAsyncError(completion: @escaping (Result<Any?, Error>) -> Void)
+  /// Responds with an error from an async void function.
+  func throwAsyncErrorFromVoid(completion: @escaping (Result<Void, Error>) -> Void)
+  func callFlutterNoop(completion: @escaping (Result<Void, Error>) -> Void)
+  func callFlutterEcho(_ everything: AllTypes, completion: @escaping (Result<AllTypes, Error>) -> Void)
+  func callFlutterSendMultipleNullableTypes(aBool aNullableBool: Bool?, anInt aNullableInt: Int32?, aString aNullableString: String?, completion: @escaping (Result<AllNullableTypes, Error>) -> Void)
+  func callFlutterEcho(_ aBool: Bool, completion: @escaping (Result<Bool, Error>) -> Void)
+  func callFlutterEcho(_ anInt: Int32, completion: @escaping (Result<Int32, Error>) -> Void)
+  func callFlutterEcho(_ aDouble: Double, completion: @escaping (Result<Double, Error>) -> Void)
+  func callFlutterEcho(_ aString: String, completion: @escaping (Result<String, Error>) -> Void)
+  func callFlutterEcho(_ aList: FlutterStandardTypedData, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void)
+  func callFlutterEcho(_ aList: [Any?], completion: @escaping (Result<[Any?], Error>) -> Void)
+  func callFlutterEcho(_ aMap: [String?: Any?], completion: @escaping (Result<[String?: Any?], Error>) -> Void)
+  func callFlutterEchoNullable(_ aBool: Bool?, completion: @escaping (Result<Bool?, Error>) -> Void)
+  func callFlutterEchoNullable(_ anInt: Int32?, completion: @escaping (Result<Int32?, Error>) -> Void)
+  func callFlutterEchoNullable(_ aDouble: Double?, completion: @escaping (Result<Double?, Error>) -> Void)
+  func callFlutterEchoNullable(_ aString: String?, completion: @escaping (Result<String?, Error>) -> Void)
+  func callFlutterEchoNullable(_ aList: FlutterStandardTypedData?, completion: @escaping (Result<FlutterStandardTypedData?, Error>) -> Void)
+  func callFlutterEchoNullable(_ aList: [Any?]?, completion: @escaping (Result<[Any?]?, Error>) -> Void)
+  func callFlutterEchoNullable(_ aMap: [String?: Any?]?, completion: @escaping (Result<[String?: Any?]?, Error>) -> Void)
 }
 
 /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
@@ -622,8 +626,13 @@
     let noopAsyncChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostIntegrationCoreApi.noopAsync", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       noopAsyncChannel.setMessageHandler { _, reply in
-        api.noopAsync() {
-          reply(wrapResult(nil))
+        api.noopAsync() { result in
+          switch result {
+            case .success:
+              reply(wrapResult(nil))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -636,17 +645,59 @@
         let args = message as! [Any?]
         let aStringArg = args[0] as! String
         api.echoAsync(aStringArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
       echoAsyncStringChannel.setMessageHandler(nil)
     }
+    /// Responds with an error from an async function returning a value.
+    let throwAsyncErrorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostIntegrationCoreApi.throwAsyncError", binaryMessenger: binaryMessenger, codec: codec)
+    if let api = api {
+      throwAsyncErrorChannel.setMessageHandler { _, reply in
+        api.throwAsyncError() { result in
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
+        }
+      }
+    } else {
+      throwAsyncErrorChannel.setMessageHandler(nil)
+    }
+    /// Responds with an error from an async void function.
+    let throwAsyncErrorFromVoidChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostIntegrationCoreApi.throwAsyncErrorFromVoid", binaryMessenger: binaryMessenger, codec: codec)
+    if let api = api {
+      throwAsyncErrorFromVoidChannel.setMessageHandler { _, reply in
+        api.throwAsyncErrorFromVoid() { result in
+          switch result {
+            case .success:
+              reply(wrapResult(nil))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
+        }
+      }
+    } else {
+      throwAsyncErrorFromVoidChannel.setMessageHandler(nil)
+    }
     let callFlutterNoopChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostIntegrationCoreApi.callFlutterNoop", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       callFlutterNoopChannel.setMessageHandler { _, reply in
-        api.callFlutterNoop() {
-          reply(wrapResult(nil))
+        api.callFlutterNoop() { result in
+          switch result {
+            case .success:
+              reply(wrapResult(nil))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -658,7 +709,12 @@
         let args = message as! [Any?]
         let everythingArg = args[0] as! AllTypes
         api.callFlutterEcho(everythingArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -672,7 +728,12 @@
         let aNullableIntArg = args[1] as? Int32
         let aNullableStringArg = args[2] as? String
         api.callFlutterSendMultipleNullableTypes(aBool: aNullableBoolArg, anInt: aNullableIntArg, aString: aNullableStringArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -684,7 +745,12 @@
         let args = message as! [Any?]
         let aBoolArg = args[0] as! Bool
         api.callFlutterEcho(aBoolArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -696,7 +762,12 @@
         let args = message as! [Any?]
         let anIntArg = args[0] as! Int32
         api.callFlutterEcho(anIntArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -708,7 +779,12 @@
         let args = message as! [Any?]
         let aDoubleArg = args[0] as! Double
         api.callFlutterEcho(aDoubleArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -720,7 +796,12 @@
         let args = message as! [Any?]
         let aStringArg = args[0] as! String
         api.callFlutterEcho(aStringArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -732,7 +813,12 @@
         let args = message as! [Any?]
         let aListArg = args[0] as! FlutterStandardTypedData
         api.callFlutterEcho(aListArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -744,7 +830,12 @@
         let args = message as! [Any?]
         let aListArg = args[0] as! [Any?]
         api.callFlutterEcho(aListArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -756,7 +847,12 @@
         let args = message as! [Any?]
         let aMapArg = args[0] as! [String?: Any?]
         api.callFlutterEcho(aMapArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -768,7 +864,12 @@
         let args = message as! [Any?]
         let aBoolArg = args[0] as? Bool
         api.callFlutterEchoNullable(aBoolArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -780,7 +881,12 @@
         let args = message as! [Any?]
         let anIntArg = args[0] as? Int32
         api.callFlutterEchoNullable(anIntArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -792,7 +898,12 @@
         let args = message as! [Any?]
         let aDoubleArg = args[0] as? Double
         api.callFlutterEchoNullable(aDoubleArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -804,7 +915,12 @@
         let args = message as! [Any?]
         let aStringArg = args[0] as? String
         api.callFlutterEchoNullable(aStringArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -816,7 +932,12 @@
         let args = message as! [Any?]
         let aListArg = args[0] as? FlutterStandardTypedData
         api.callFlutterEchoNullable(aListArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -828,7 +949,12 @@
         let args = message as! [Any?]
         let aListArg = args[0] as? [Any?]
         api.callFlutterEchoNullable(aListArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
@@ -840,7 +966,12 @@
         let args = message as! [Any?]
         let aMapArg = args[0] as? [String?: Any?]
         api.callFlutterEchoNullable(aMapArg) { result in
-          reply(wrapResult(result))
+          switch result {
+            case .success(let res):
+              reply(wrapResult(res))
+            case .failure(let error):
+              reply(wrapError(error))
+          }
         }
       }
     } else {
diff --git a/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift b/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift
index c9c1144..54b3d40 100644
--- a/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift
+++ b/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift
@@ -5,6 +5,8 @@
 import Cocoa
 import FlutterMacOS
 
+extension FlutterError: Error {}
+
 /**
  * This plugin handles the native side of the integration tests in
  * example/integration_test/.
@@ -22,8 +24,8 @@
   }
 
   // MARK: HostIntegrationCoreApi implementation
-
   func noop() {
+
   }
 
   func echo(_ everything: AllTypes) -> AllTypes {
@@ -35,7 +37,7 @@
   }
 
   func throwError() throws {
-    throw ErrType.thrownErrow
+    throw FlutterError(code: "code", message: "message", details: "details")
   }
 
   func echo(_ anInt: Int32) -> Int32 {
@@ -99,96 +101,164 @@
     return aNullableObject
   }
 
-  func noopAsync(completion: @escaping () -> Void) {
-    completion()
+  func noopAsync(completion: @escaping (Result<Void, Error>) -> Void) {
+    completion(.success(Void()))
   }
 
-  func echoAsync(_ aString: String, completion: @escaping (String) -> Void) {
-    completion(aString)
+  func echoAsync(_ aString: String, completion: @escaping (Result<String, Error>) -> Void) {
+    let result: Result<String, Error>
+    result = .success(aString)
+    completion(result)
   }
 
-  func callFlutterNoop(completion: @escaping () -> Void) {
+  func throwAsyncError(completion: @escaping (Result<Any?, Error>) -> Void) {
+    completion(.failure(FlutterError(code: "code", message: "message", details: "details")))
+  }
+
+  func throwAsyncErrorFromVoid(completion: @escaping (Result<Void, Error>) -> Void) {
+    completion(.failure(FlutterError(code: "code", message: "message", details: "details")))
+  }
+
+  func callFlutterNoop(completion: @escaping (Result<Void, Error>) -> Void) {
     flutterAPI.noop() {
-      completion()
+      completion(.success(Void()))
     }
   }
 
-  func callFlutterEcho(_ everything: AllTypes, completion: @escaping (AllTypes) -> Void) {
-      flutterAPI.echo(everything) { completion($0) }
+  func callFlutterEcho(_ everything: AllTypes, completion: @escaping (Result<AllTypes, Error>) -> Void) {
+    flutterAPI.echo(everything) { 
+      let result: Result<AllTypes, Error>
+      result = .success($0)
+      completion(result) 
+    }
   }
 
   func callFlutterSendMultipleNullableTypes(
-    aBool aNullableBool: Bool?,
-    anInt aNullableInt: Int32?,
-    aString aNullableString: String?,
-    completion: @escaping (AllNullableTypes) -> Void
+    aBool aNullableBool: Bool?, 
+    anInt aNullableInt: Int32?, 
+    aString aNullableString: String?, 
+    completion: @escaping (Result<AllNullableTypes, Error>) -> Void
   ) {
     flutterAPI.sendMultipleNullableTypes(
       aBool: aNullableBool,
       anInt: aNullableInt,
       aString: aNullableString
     ) {
-      completion($0)
+      let result: Result<AllNullableTypes, Error>
+      result = .success($0)
+      completion(result)
     }
   }
 
-  func callFlutterEcho(_ aBool: Bool, completion: @escaping (Bool) -> Void) {
-    flutterAPI.echo(aBool) { completion($0) }
+  func callFlutterEcho(_ aBool: Bool, completion: @escaping (Result<Bool, Error>) -> Void) {
+    flutterAPI.echo(aBool) { 
+      let result: Result<Bool, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEcho(_ anInt: Int32, completion: @escaping (Int32) -> Void) {
-    flutterAPI.echo(anInt) { completion($0) }
+  func callFlutterEcho(_ anInt: Int32, completion: @escaping (Result<Int32, Error>) -> Void) {
+    flutterAPI.echo(anInt) { 
+      let result: Result<Int32, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEcho(_ aDouble: Double, completion: @escaping (Double) -> Void) {
-    flutterAPI.echo(aDouble) { completion($0) }
+  func callFlutterEcho(_ aDouble: Double,  completion: @escaping (Result<Double, Error>) -> Void) {
+    flutterAPI.echo(aDouble) { 
+      let result: Result<Double, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEcho(_ aString: String, completion: @escaping (String) -> Void) {
-    flutterAPI.echo(aString) { completion($0) }
+  func callFlutterEcho(_ aString: String, completion: @escaping (Result<String, Error>) -> Void) {
+    flutterAPI.echo(aString) { 
+      let result: Result<String, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEcho(_ aList: FlutterStandardTypedData, completion: @escaping (FlutterStandardTypedData) -> Void) {
-    flutterAPI.echo(aList) { completion($0) }
+  func callFlutterEcho(_ aList: FlutterStandardTypedData, completion: @escaping (Result<FlutterStandardTypedData, Error>) -> Void) {
+    flutterAPI.echo(aList) { 
+      let result: Result<FlutterStandardTypedData, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEcho(_ aList: [Any?], completion: @escaping ([Any?]) -> Void) {
-    flutterAPI.echo(aList) { completion($0) }
+  func callFlutterEcho(_ aList: [Any?], completion: @escaping (Result<[Any?], Error>) -> Void) {
+    flutterAPI.echo(aList) { 
+      let result: Result<[Any?], Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEcho(_ aMap: [String? : Any?], completion: @escaping ([String? : Any?]) -> Void) {
-    flutterAPI.echo(aMap) { completion($0) }
+  func callFlutterEcho(_ aMap: [String? : Any?], completion: @escaping (Result<[String? : Any?], Error>) -> Void) {
+    flutterAPI.echo(aMap) { 
+      let result: Result<[String? : Any?], Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEchoNullable(_ aBool: Bool?, completion: @escaping (Bool?) -> Void) {
-    flutterAPI.echoNullable(aBool) { completion($0) }
+  func callFlutterEchoNullable(_ aBool: Bool?, completion: @escaping (Result<Bool?, Error>) -> Void) {
+    flutterAPI.echoNullable(aBool) { 
+      let result: Result<Bool?, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEchoNullable(_ anInt: Int32?, completion: @escaping (Int32?) -> Void) {
-    flutterAPI.echoNullable(anInt) { completion($0) }
+  func callFlutterEchoNullable(_ anInt: Int32?, completion: @escaping (Result<Int32?, Error>) -> Void) {
+    flutterAPI.echoNullable(anInt) { 
+      let result: Result<Int32?, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEchoNullable(_ aDouble: Double?, completion: @escaping (Double?) -> Void) {
-    flutterAPI.echoNullable(aDouble) { completion($0) }
+  func callFlutterEchoNullable(_ aDouble: Double?, completion: @escaping (Result<Double?, Error>) -> Void) {
+    flutterAPI.echoNullable(aDouble) { 
+      let result: Result<Double?, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEchoNullable(_ aString: String?, completion: @escaping (String?) -> Void) {
-    flutterAPI.echoNullable(aString) { completion($0) }
+  func callFlutterEchoNullable(_ aString: String?, completion: @escaping (Result<String?, Error>) -> Void) {
+    flutterAPI.echoNullable(aString) { 
+      let result: Result<String?, Error>
+      result = .success($0)
+      completion(result)
+    }
+  }
+  
+  func callFlutterEchoNullable(_ aList: FlutterStandardTypedData?, completion: @escaping (Result<FlutterStandardTypedData?, Error>) -> Void) {
+    flutterAPI.echoNullable(aList) { 
+      let result: Result<FlutterStandardTypedData?, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEchoNullable(_ aList: FlutterStandardTypedData?, completion: @escaping (FlutterStandardTypedData?) -> Void) {
-    flutterAPI.echoNullable(aList) { completion($0) }
+  func callFlutterEchoNullable(_ aList: [Any?]?, completion: @escaping (Result<[Any?]?, Error>) -> Void) {
+    flutterAPI.echoNullable(aList) { 
+      let result: Result<[Any?]?, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
 
-  func callFlutterEchoNullable(_ aList: [Any?]?, completion: @escaping ([Any?]?) -> Void) {
-    flutterAPI.echoNullable(aList) { completion($0) }
+  func callFlutterEchoNullable(_ aMap: [String? : Any?]?, completion: @escaping (Result<[String? : Any?]?, Error>) -> Void) {
+    flutterAPI.echoNullable(aMap) { 
+      let result: Result<[String? : Any?]?, Error>
+      result = .success($0)
+      completion(result)
+    }
   }
-
-  func callFlutterEchoNullable(_ aMap: [String? : Any?]?, completion: @escaping ([String? : Any?]?) -> Void) {
-    flutterAPI.echoNullable(aMap) { completion($0) }
-  }
-}
-
-enum ErrType: Error {
-  case thrownErrow
 }
\ No newline at end of file
diff --git a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp
index b5d9f52..d903af2 100644
--- a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp
+++ b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.cpp
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 #undef _HAS_EXCEPTIONS
@@ -1266,6 +1266,68 @@
   {
     auto channel = std::make_unique<BasicMessageChannel<>>(
         binary_messenger,
+        "dev.flutter.pigeon.HostIntegrationCoreApi.throwAsyncError",
+        &GetCodec());
+    if (api != nullptr) {
+      channel->SetMessageHandler(
+          [api](const EncodableValue& message,
+                const flutter::MessageReply<EncodableValue>& reply) {
+            try {
+              api->ThrowAsyncError(
+                  [reply](ErrorOr<std::optional<EncodableValue>>&& output) {
+                    if (output.has_error()) {
+                      reply(WrapError(output.error()));
+                      return;
+                    }
+                    EncodableList wrapped;
+                    auto output_optional = std::move(output).TakeValue();
+                    if (output_optional) {
+                      wrapped.push_back(
+                          EncodableValue(std::move(output_optional).value()));
+                    } else {
+                      wrapped.push_back(EncodableValue());
+                    }
+                    reply(EncodableValue(std::move(wrapped)));
+                  });
+            } catch (const std::exception& exception) {
+              reply(WrapError(exception.what()));
+            }
+          });
+    } else {
+      channel->SetMessageHandler(nullptr);
+    }
+  }
+  {
+    auto channel = std::make_unique<BasicMessageChannel<>>(
+        binary_messenger,
+        "dev.flutter.pigeon.HostIntegrationCoreApi.throwAsyncErrorFromVoid",
+        &GetCodec());
+    if (api != nullptr) {
+      channel->SetMessageHandler(
+          [api](const EncodableValue& message,
+                const flutter::MessageReply<EncodableValue>& reply) {
+            try {
+              api->ThrowAsyncErrorFromVoid(
+                  [reply](std::optional<FlutterError>&& output) {
+                    if (output.has_value()) {
+                      reply(WrapError(output.value()));
+                      return;
+                    }
+                    EncodableList wrapped;
+                    wrapped.push_back(EncodableValue());
+                    reply(EncodableValue(std::move(wrapped)));
+                  });
+            } catch (const std::exception& exception) {
+              reply(WrapError(exception.what()));
+            }
+          });
+    } else {
+      channel->SetMessageHandler(nullptr);
+    }
+  }
+  {
+    auto channel = std::make_unique<BasicMessageChannel<>>(
+        binary_messenger,
         "dev.flutter.pigeon.HostIntegrationCoreApi.callFlutterNoop",
         &GetCodec());
     if (api != nullptr) {
diff --git a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h
index 246425c..1cff1cd 100644
--- a/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h
+++ b/packages/pigeon/platform_tests/test_plugin/windows/pigeon/core_tests.gen.h
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
-// Autogenerated from Pigeon (v7.1.5), do not edit directly.
+// Autogenerated from Pigeon (v7.2.0), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 #ifndef PIGEON_CORE_TESTS_GEN_H_
@@ -325,6 +325,13 @@
   virtual void EchoAsyncString(
       const std::string& a_string,
       std::function<void(ErrorOr<std::string> reply)> result) = 0;
+  // Responds with an error from an async function returning a value.
+  virtual void ThrowAsyncError(
+      std::function<void(ErrorOr<std::optional<flutter::EncodableValue>> reply)>
+          result) = 0;
+  // Responds with an error from an async void function.
+  virtual void ThrowAsyncErrorFromVoid(
+      std::function<void(std::optional<FlutterError> reply)> result) = 0;
   virtual void CallFlutterNoop(
       std::function<void(std::optional<FlutterError> reply)> result) = 0;
   virtual void CallFlutterEchoAllTypes(
diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp
index 56c0a3a..98d1d09 100644
--- a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp
+++ b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.cpp
@@ -180,6 +180,17 @@
   result(a_string);
 }
 
+void TestPlugin::ThrowAsyncError(
+    std::function<void(ErrorOr<std::optional<flutter::EncodableValue>> reply)>
+        result) {
+  result(FlutterError("code", "message", EncodableValue("details")));
+}
+
+void TestPlugin::ThrowAsyncErrorFromVoid(
+    std::function<void(std::optional<FlutterError> reply)> result) {
+  result(FlutterError("code", "message", EncodableValue("details")));
+}
+
 void TestPlugin::CallFlutterNoop(
     std::function<void(std::optional<FlutterError> reply)> result) {
   flutter_api_->Noop([result]() { result(std::nullopt); },
diff --git a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h
index aa0e19c..c5e18b5 100644
--- a/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h
+++ b/packages/pigeon/platform_tests/test_plugin/windows/test_plugin.h
@@ -78,6 +78,15 @@
       const std::string& a_string,
       std::function<void(core_tests_pigeontest::ErrorOr<std::string> reply)>
           result) override;
+  void ThrowAsyncError(
+      std::function<void(
+          core_tests_pigeontest::ErrorOr<std::optional<flutter::EncodableValue>>
+              reply)>
+          result) override;
+  void ThrowAsyncErrorFromVoid(
+      std::function<
+          void(std::optional<core_tests_pigeontest::FlutterError> reply)>
+          result) override;
   void CallFlutterNoop(
       std::function<
           void(std::optional<core_tests_pigeontest::FlutterError> reply)>
diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml
index 6d8514e..f0d17a4 100644
--- a/packages/pigeon/pubspec.yaml
+++ b/packages/pigeon/pubspec.yaml
@@ -2,7 +2,7 @@
 description: Code generator tool to make communication between Flutter and the host platform type-safe and easier.
 repository: https://github.com/flutter/packages/tree/main/packages/pigeon
 issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3Apigeon
-version: 7.1.5 # This must match the version in lib/generator_tools.dart
+version: 7.2.0 # This must match the version in lib/generator_tools.dart
 
 environment:
   sdk: ">=2.12.0 <3.0.0"
diff --git a/packages/pigeon/test/kotlin_generator_test.dart b/packages/pigeon/test/kotlin_generator_test.dart
index 1887062..0ab6df6 100644
--- a/packages/pigeon/test/kotlin_generator_test.dart
+++ b/packages/pigeon/test/kotlin_generator_test.dart
@@ -186,9 +186,9 @@
         if (api != null) {
           channel.setMessageHandler { message, reply ->
             var wrapped = listOf<Any?>()
+            val args = message as List<Any?>
+            val inputArg = args[0] as Input
             try {
-              val args = message as List<Any?>
-              val inputArg = args[0] as Input
               wrapped = listOf<Any?>(api.doSomething(inputArg))
             } catch (exception: Error) {
               wrapped = wrapError(exception)
@@ -668,7 +668,7 @@
     final String code = sink.toString();
     expect(code, contains('interface Api'));
     expect(code, contains('api.doSomething(argArg) {'));
-    expect(code, contains('reply.reply(wrapResult(it))'));
+    expect(code, contains('reply.reply(wrapResult(data))'));
   });
 
   test('gen one async Flutter Api', () {
@@ -1063,7 +1063,7 @@
     const KotlinGenerator generator = KotlinGenerator();
     generator.generate(kotlinOptions, root, sink);
     final String code = sink.toString();
-    expect(code, contains('fun doit(callback: (Long?) -> Unit'));
+    expect(code, contains('fun doit(callback: (Result<Long?>) -> Unit'));
   });
 
   test('nullable argument host', () {
diff --git a/packages/pigeon/test/swift_generator_test.dart b/packages/pigeon/test/swift_generator_test.dart
index 4f42a0f..e4b1b4c 100644
--- a/packages/pigeon/test/swift_generator_test.dart
+++ b/packages/pigeon/test/swift_generator_test.dart
@@ -499,7 +499,7 @@
     final String code = sink.toString();
     expect(code, contains('protocol Api'));
     expect(code, contains('api.doSomething(arg: argArg) { result in'));
-    expect(code, contains('reply(wrapResult(result))'));
+    expect(code, contains('reply(wrapResult(res))'));
   });
 
   test('gen one async Flutter Api', () {
@@ -884,7 +884,10 @@
     const SwiftGenerator generator = SwiftGenerator();
     generator.generate(swiftOptions, root, sink);
     final String code = sink.toString();
-    expect(code, contains('func doit(completion: @escaping (Int32?) -> Void'));
+    expect(
+        code,
+        contains(
+            'func doit(completion: @escaping (Result<Int32?, Error>) -> Void'));
   });
 
   test('nullable argument host', () {