[pigeon] Swift host error handling (#3084)

* 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++

* Revert "Async error handling"

This reverts commit a07190cef481f3d767236ea16f383658a8d7fc4d.

* gen

* nit
diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md
index 891bce4..95f3bb1 100644
--- a/packages/pigeon/CHANGELOG.md
+++ b/packages/pigeon/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 7.1.2
+
+* [swift] Adds error handling to sync host api methods.
+
 ## 7.1.1
 
 * [c++] Fixes handling of the `cpp*` options in `@ConfigurePigeon` annotations.
diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart
index 784b201..1d263c1 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.1';
+const String pigeonVersion = '7.1.2';
 
 /// Read all the content from [stdin] to a String.
 String readStdin() {
diff --git a/packages/pigeon/lib/swift_generator.dart b/packages/pigeon/lib/swift_generator.dart
index 6109b8d..5d3d15c 100644
--- a/packages/pigeon/lib/swift_generator.dart
+++ b/packages/pigeon/lib/swift_generator.dart
@@ -404,10 +404,11 @@
           argSignature.add('completion: @escaping ($returnType) -> Void');
           indent.writeln('func ${components.name}(${argSignature.join(', ')})');
         } else if (method.returnType.isVoid) {
-          indent.writeln('func ${components.name}(${argSignature.join(', ')})');
+          indent.writeln(
+              'func ${components.name}(${argSignature.join(', ')}) throws');
         } else {
           indent.writeln(
-              'func ${components.name}(${argSignature.join(', ')}) -> $returnType');
+              'func ${components.name}(${argSignature.join(', ')}) throws -> $returnType');
         }
       }
     });
@@ -465,8 +466,9 @@
                   }
                 });
               }
+              final String tryStatement = method.isAsynchronous ? '' : 'try ';
               final String call =
-                  'api.${components.name}(${methodArgument.join(', ')})';
+                  '${tryStatement}api.${components.name}(${methodArgument.join(', ')})';
               if (method.isAsynchronous) {
                 indent.write('$call ');
                 if (method.returnType.isVoid) {
@@ -479,13 +481,19 @@
                   });
                 }
               } else {
-                if (method.returnType.isVoid) {
-                  indent.writeln(call);
-                  indent.writeln('reply(wrapResult(nil))');
-                } else {
-                  indent.writeln('let result = $call');
-                  indent.writeln('reply(wrapResult(result))');
-                }
+                indent.write('do ');
+                indent.addScoped('{', '}', () {
+                  if (method.returnType.isVoid) {
+                    indent.writeln(call);
+                    indent.writeln('reply(wrapResult(nil))');
+                  } else {
+                    indent.writeln('let result = $call');
+                    indent.writeln('reply(wrapResult(result))');
+                  }
+                }, addTrailingNewline: false);
+                indent.addScoped(' catch {', '}', () {
+                  indent.writeln('reply(wrapError(error))');
+                });
               }
             });
           }, addTrailingNewline: false);
@@ -595,13 +603,22 @@
 
   void _writeWrapError(Indent indent) {
     indent.newln();
-    indent.write('private func wrapError(_ error: FlutterError) -> [Any?] ');
+    indent.write('private func wrapError(_ error: Any) -> [Any?] ');
     indent.addScoped('{', '}', () {
+      indent.write('if let flutterError = error as? FlutterError ');
+      indent.addScoped('{', '}', () {
+        indent.write('return ');
+        indent.addScoped('[', ']', () {
+          indent.writeln('flutterError.code,');
+          indent.writeln('flutterError.message,');
+          indent.writeln('flutterError.details');
+        });
+      });
       indent.write('return ');
       indent.addScoped('[', ']', () {
-        indent.writeln('error.code,');
-        indent.writeln('error.message,');
-        indent.writeln('error.details');
+        indent.writeln(r'"\(error)",');
+        indent.writeln(r'"\(type(of: error))",');
+        indent.writeln(r'"Stacktrace: \(Thread.callStackSymbols)"');
       });
     });
   }
diff --git a/packages/pigeon/mock_handler_tester/test/message.dart b/packages/pigeon/mock_handler_tester/test/message.dart
index 9cd0236..3d6f886 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.0.5), do not edit directly.
+// Autogenerated from Pigeon (v7.1.2), 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 152a076..7dd3a29 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.0.5), do not edit directly.
+// Autogenerated from Pigeon (v7.1.2), 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/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 3c8cb33..e7e151c 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.1), do not edit directly.
+// Autogenerated from Pigeon (v7.1.2), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 package com.example.alternate_language_test_plugin;
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 24cccf7..8bc97a6 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.1), do not edit directly.
+// Autogenerated from Pigeon (v7.1.2), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 #import <Foundation/Foundation.h>
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 1a5bf69..193eb8d 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.1), do not edit directly.
+// Autogenerated from Pigeon (v7.1.2), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 #import "CoreTests.gen.h"
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 6fb1023..14e2616 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.0.5), do not edit directly.
+// Autogenerated from Pigeon (v7.1.2), 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/flutter_unittests.gen.dart b/packages/pigeon/platform_tests/flutter_null_safe_unit_tests/lib/flutter_unittests.gen.dart
index 8b416c4..e3f3774 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.0.5), do not edit directly.
+// Autogenerated from Pigeon (v7.1.2), 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 1d0d98e..fc368e0 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.0.5), do not edit directly.
+// Autogenerated from Pigeon (v7.1.2), 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 aea9caa..1dba981 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.0.5), do not edit directly.
+// Autogenerated from Pigeon (v7.1.2), 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 ee30169..0959a91 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.0.5), do not edit directly.
+// Autogenerated from Pigeon (v7.1.2), 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 9e2d4b6..05e9e5b 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.0.5), do not edit directly.
+// Autogenerated from Pigeon (v7.1.2), 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 0051028..cb5c01d 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.0.5), do not edit directly.
+// Autogenerated from Pigeon (v7.1.2), 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 87bc718..78aa5a8 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
@@ -231,10 +231,7 @@
       expect(() async {
         await api.throwError();
       }, throwsA(isA<PlatformException>()));
-    },
-        // Currently unimplementable for Swift:
-        // https://github.com/flutter/flutter/issues/112483
-        skip: targetGenerator == TargetGenerator.swift);
+    });
 
     testWidgets('nested objects can be sent correctly', (WidgetTester _) async {
       final HostIntegrationCoreApi api = HostIntegrationCoreApi();
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 4db24a8..14e2616 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.1), do not edit directly.
+// Autogenerated from Pigeon (v7.1.2), 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/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 81ddf7f..decb7ae 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.1), do not edit directly.
+// 
+// Autogenerated from Pigeon (v7.1.2), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 package com.example.test_plugin
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 5bf806e..e9f6389 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.1), do not edit directly.
+// 
+// Autogenerated from Pigeon (v7.1.2), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 import Foundation
@@ -20,11 +20,18 @@
   return [result]
 }
 
-private func wrapError(_ error: FlutterError) -> [Any?] {
+private func wrapError(_ error: Any) -> [Any?] {
+  if let flutterError = error as? FlutterError {
+    return [
+      flutterError.code,
+      flutterError.message,
+      flutterError.details
+    ]
+  }
   return [
-    error.code,
-    error.message,
-    error.details
+    "\(error)",
+    "\(type(of: error))",
+    "Stacktrace: \(Thread.callStackSymbols)"
   ]
 }
 
@@ -110,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,
@@ -236,45 +243,45 @@
 protocol HostIntegrationCoreApi {
   /// A no-op function taking no arguments and returning no value, to sanity
   /// test basic calling.
-  func noop()
+  func noop() throws
   /// Returns the passed object, to test serialization and deserialization.
-  func echo(_ everything: AllTypes) -> AllTypes
+  func echo(_ everything: AllTypes) throws -> AllTypes
   /// Returns the passed object, to test serialization and deserialization.
-  func echo(_ everything: AllNullableTypes?) -> AllNullableTypes?
+  func echo(_ everything: AllNullableTypes?) throws -> AllNullableTypes?
   /// Returns an error, to test error handling.
-  func throwError()
+  func throwError() throws
   /// Returns passed in int.
-  func echo(_ anInt: Int32) -> Int32
+  func echo(_ anInt: Int32) throws -> Int32
   /// Returns passed in double.
-  func echo(_ aDouble: Double) -> Double
+  func echo(_ aDouble: Double) throws -> Double
   /// Returns the passed in boolean.
-  func echo(_ aBool: Bool) -> Bool
+  func echo(_ aBool: Bool) throws -> Bool
   /// Returns the passed in string.
-  func echo(_ aString: String) -> String
+  func echo(_ aString: String) throws -> String
   /// Returns the passed in Uint8List.
-  func echo(_ aUint8List: FlutterStandardTypedData) -> FlutterStandardTypedData
+  func echo(_ aUint8List: FlutterStandardTypedData) throws -> FlutterStandardTypedData
   /// Returns the passed in generic Object.
-  func echo(_ anObject: Any) -> Any
+  func echo(_ anObject: Any) throws -> Any
   /// Returns the inner `aString` value from the wrapped object, to test
   /// sending of nested objects.
-  func extractNestedNullableString(from wrapper: AllNullableTypesWrapper) -> String?
+  func extractNestedNullableString(from wrapper: AllNullableTypesWrapper) throws -> String?
   /// Returns the inner `aString` value from the wrapped object, to test
   /// sending of nested objects.
-  func createNestedObject(with nullableString: String?) -> AllNullableTypesWrapper
+  func createNestedObject(with nullableString: String?) throws -> AllNullableTypesWrapper
   /// Returns passed in arguments of multiple types.
-  func sendMultipleNullableTypes(aBool aNullableBool: Bool?, anInt aNullableInt: Int32?, aString aNullableString: String?) -> AllNullableTypes
+  func sendMultipleNullableTypes(aBool aNullableBool: Bool?, anInt aNullableInt: Int32?, aString aNullableString: String?) throws -> AllNullableTypes
   /// Returns passed in int.
-  func echo(_ aNullableInt: Int32?) -> Int32?
+  func echo(_ aNullableInt: Int32?) throws -> Int32?
   /// Returns passed in double.
-  func echo(_ aNullableDouble: Double?) -> Double?
+  func echo(_ aNullableDouble: Double?) throws -> Double?
   /// Returns the passed in boolean.
-  func echo(_ aNullableBool: Bool?) -> Bool?
+  func echo(_ aNullableBool: Bool?) throws -> Bool?
   /// Returns the passed in string.
-  func echo(_ aNullableString: String?) -> String?
+  func echo(_ aNullableString: String?) throws -> String?
   /// Returns the passed in Uint8List.
-  func echo(_ aNullableUint8List: FlutterStandardTypedData?) -> FlutterStandardTypedData?
+  func echo(_ aNullableUint8List: FlutterStandardTypedData?) throws -> FlutterStandardTypedData?
   /// Returns the passed in generic Object.
-  func echo(_ aNullableObject: Any?) -> Any?
+  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)
@@ -310,8 +317,12 @@
     let noopChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostIntegrationCoreApi.noop", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       noopChannel.setMessageHandler { _, reply in
-        api.noop()
-        reply(wrapResult(nil))
+        do {
+          try api.noop()
+          reply(wrapResult(nil))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       noopChannel.setMessageHandler(nil)
@@ -322,8 +333,12 @@
       echoAllTypesChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let everythingArg = args[0] as! AllTypes
-        let result = api.echo(everythingArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(everythingArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoAllTypesChannel.setMessageHandler(nil)
@@ -334,8 +349,12 @@
       echoAllNullableTypesChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let everythingArg = args[0] as? AllNullableTypes
-        let result = api.echo(everythingArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(everythingArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoAllNullableTypesChannel.setMessageHandler(nil)
@@ -344,8 +363,12 @@
     let throwErrorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostIntegrationCoreApi.throwError", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       throwErrorChannel.setMessageHandler { _, reply in
-        api.throwError()
-        reply(wrapResult(nil))
+        do {
+          try api.throwError()
+          reply(wrapResult(nil))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       throwErrorChannel.setMessageHandler(nil)
@@ -356,8 +379,12 @@
       echoIntChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let anIntArg = args[0] as! Int32
-        let result = api.echo(anIntArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(anIntArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoIntChannel.setMessageHandler(nil)
@@ -368,8 +395,12 @@
       echoDoubleChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aDoubleArg = args[0] as! Double
-        let result = api.echo(aDoubleArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aDoubleArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoDoubleChannel.setMessageHandler(nil)
@@ -380,8 +411,12 @@
       echoBoolChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aBoolArg = args[0] as! Bool
-        let result = api.echo(aBoolArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aBoolArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoBoolChannel.setMessageHandler(nil)
@@ -392,8 +427,12 @@
       echoStringChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aStringArg = args[0] as! String
-        let result = api.echo(aStringArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aStringArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoStringChannel.setMessageHandler(nil)
@@ -404,8 +443,12 @@
       echoUint8ListChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aUint8ListArg = args[0] as! FlutterStandardTypedData
-        let result = api.echo(aUint8ListArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aUint8ListArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoUint8ListChannel.setMessageHandler(nil)
@@ -416,8 +459,12 @@
       echoObjectChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let anObjectArg = args[0]!
-        let result = api.echo(anObjectArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(anObjectArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoObjectChannel.setMessageHandler(nil)
@@ -429,8 +476,12 @@
       extractNestedNullableStringChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let wrapperArg = args[0] as! AllNullableTypesWrapper
-        let result = api.extractNestedNullableString(from: wrapperArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.extractNestedNullableString(from: wrapperArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       extractNestedNullableStringChannel.setMessageHandler(nil)
@@ -442,8 +493,12 @@
       createNestedNullableStringChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let nullableStringArg = args[0] as? String
-        let result = api.createNestedObject(with: nullableStringArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.createNestedObject(with: nullableStringArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       createNestedNullableStringChannel.setMessageHandler(nil)
@@ -456,8 +511,12 @@
         let aNullableBoolArg = args[0] as? Bool
         let aNullableIntArg = args[1] as? Int32
         let aNullableStringArg = args[2] as? String
-        let result = api.sendMultipleNullableTypes(aBool: aNullableBoolArg, anInt: aNullableIntArg, aString: aNullableStringArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.sendMultipleNullableTypes(aBool: aNullableBoolArg, anInt: aNullableIntArg, aString: aNullableStringArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       sendMultipleNullableTypesChannel.setMessageHandler(nil)
@@ -468,8 +527,12 @@
       echoNullableIntChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aNullableIntArg = args[0] as? Int32
-        let result = api.echo(aNullableIntArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aNullableIntArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoNullableIntChannel.setMessageHandler(nil)
@@ -480,8 +543,12 @@
       echoNullableDoubleChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aNullableDoubleArg = args[0] as? Double
-        let result = api.echo(aNullableDoubleArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aNullableDoubleArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoNullableDoubleChannel.setMessageHandler(nil)
@@ -492,8 +559,12 @@
       echoNullableBoolChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aNullableBoolArg = args[0] as? Bool
-        let result = api.echo(aNullableBoolArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aNullableBoolArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoNullableBoolChannel.setMessageHandler(nil)
@@ -504,8 +575,12 @@
       echoNullableStringChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aNullableStringArg = args[0] as? String
-        let result = api.echo(aNullableStringArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aNullableStringArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoNullableStringChannel.setMessageHandler(nil)
@@ -516,8 +591,12 @@
       echoNullableUint8ListChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aNullableUint8ListArg = args[0] as? FlutterStandardTypedData
-        let result = api.echo(aNullableUint8ListArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aNullableUint8ListArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoNullableUint8ListChannel.setMessageHandler(nil)
@@ -528,8 +607,12 @@
       echoNullableObjectChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aNullableObjectArg = args[0]
-        let result = api.echo(aNullableObjectArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aNullableObjectArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoNullableObjectChannel.setMessageHandler(nil)
@@ -974,7 +1057,7 @@
 ///
 /// Generated protocol from Pigeon that represents a handler of messages from Flutter.
 protocol HostTrivialApi {
-  func noop()
+  func noop() throws
 }
 
 /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
@@ -985,8 +1068,12 @@
     let noopChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostTrivialApi.noop", binaryMessenger: binaryMessenger)
     if let api = api {
       noopChannel.setMessageHandler { _, reply in
-        api.noop()
-        reply(wrapResult(nil))
+        do {
+          try api.noop()
+          reply(wrapResult(nil))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       noopChannel.setMessageHandler(nil)
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 edec42b..cd3a07f 100644
--- a/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift
+++ b/packages/pigeon/platform_tests/test_plugin/ios/Classes/TestPlugin.swift
@@ -24,6 +24,7 @@
   // MARK: HostIntegrationCoreApi implementation
 
   func noop() {
+
   }
 
   func echo(_ everything: AllTypes) -> AllTypes {
@@ -34,9 +35,8 @@
     return everything
   }
 
-  func throwError() {
-    // TODO(stuartmorgan): Implement this. See
-    // https://github.com/flutter/flutter/issues/112483
+  func throwError() throws {
+    throw ErrType.thrownErrow
   }
 
   func echo(_ anInt: Int32) -> Int32 {
@@ -189,3 +189,7 @@
     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 5bf806e..e9f6389 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.1), do not edit directly.
+// 
+// Autogenerated from Pigeon (v7.1.2), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 import Foundation
@@ -20,11 +20,18 @@
   return [result]
 }
 
-private func wrapError(_ error: FlutterError) -> [Any?] {
+private func wrapError(_ error: Any) -> [Any?] {
+  if let flutterError = error as? FlutterError {
+    return [
+      flutterError.code,
+      flutterError.message,
+      flutterError.details
+    ]
+  }
   return [
-    error.code,
-    error.message,
-    error.details
+    "\(error)",
+    "\(type(of: error))",
+    "Stacktrace: \(Thread.callStackSymbols)"
   ]
 }
 
@@ -110,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,
@@ -236,45 +243,45 @@
 protocol HostIntegrationCoreApi {
   /// A no-op function taking no arguments and returning no value, to sanity
   /// test basic calling.
-  func noop()
+  func noop() throws
   /// Returns the passed object, to test serialization and deserialization.
-  func echo(_ everything: AllTypes) -> AllTypes
+  func echo(_ everything: AllTypes) throws -> AllTypes
   /// Returns the passed object, to test serialization and deserialization.
-  func echo(_ everything: AllNullableTypes?) -> AllNullableTypes?
+  func echo(_ everything: AllNullableTypes?) throws -> AllNullableTypes?
   /// Returns an error, to test error handling.
-  func throwError()
+  func throwError() throws
   /// Returns passed in int.
-  func echo(_ anInt: Int32) -> Int32
+  func echo(_ anInt: Int32) throws -> Int32
   /// Returns passed in double.
-  func echo(_ aDouble: Double) -> Double
+  func echo(_ aDouble: Double) throws -> Double
   /// Returns the passed in boolean.
-  func echo(_ aBool: Bool) -> Bool
+  func echo(_ aBool: Bool) throws -> Bool
   /// Returns the passed in string.
-  func echo(_ aString: String) -> String
+  func echo(_ aString: String) throws -> String
   /// Returns the passed in Uint8List.
-  func echo(_ aUint8List: FlutterStandardTypedData) -> FlutterStandardTypedData
+  func echo(_ aUint8List: FlutterStandardTypedData) throws -> FlutterStandardTypedData
   /// Returns the passed in generic Object.
-  func echo(_ anObject: Any) -> Any
+  func echo(_ anObject: Any) throws -> Any
   /// Returns the inner `aString` value from the wrapped object, to test
   /// sending of nested objects.
-  func extractNestedNullableString(from wrapper: AllNullableTypesWrapper) -> String?
+  func extractNestedNullableString(from wrapper: AllNullableTypesWrapper) throws -> String?
   /// Returns the inner `aString` value from the wrapped object, to test
   /// sending of nested objects.
-  func createNestedObject(with nullableString: String?) -> AllNullableTypesWrapper
+  func createNestedObject(with nullableString: String?) throws -> AllNullableTypesWrapper
   /// Returns passed in arguments of multiple types.
-  func sendMultipleNullableTypes(aBool aNullableBool: Bool?, anInt aNullableInt: Int32?, aString aNullableString: String?) -> AllNullableTypes
+  func sendMultipleNullableTypes(aBool aNullableBool: Bool?, anInt aNullableInt: Int32?, aString aNullableString: String?) throws -> AllNullableTypes
   /// Returns passed in int.
-  func echo(_ aNullableInt: Int32?) -> Int32?
+  func echo(_ aNullableInt: Int32?) throws -> Int32?
   /// Returns passed in double.
-  func echo(_ aNullableDouble: Double?) -> Double?
+  func echo(_ aNullableDouble: Double?) throws -> Double?
   /// Returns the passed in boolean.
-  func echo(_ aNullableBool: Bool?) -> Bool?
+  func echo(_ aNullableBool: Bool?) throws -> Bool?
   /// Returns the passed in string.
-  func echo(_ aNullableString: String?) -> String?
+  func echo(_ aNullableString: String?) throws -> String?
   /// Returns the passed in Uint8List.
-  func echo(_ aNullableUint8List: FlutterStandardTypedData?) -> FlutterStandardTypedData?
+  func echo(_ aNullableUint8List: FlutterStandardTypedData?) throws -> FlutterStandardTypedData?
   /// Returns the passed in generic Object.
-  func echo(_ aNullableObject: Any?) -> Any?
+  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)
@@ -310,8 +317,12 @@
     let noopChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostIntegrationCoreApi.noop", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       noopChannel.setMessageHandler { _, reply in
-        api.noop()
-        reply(wrapResult(nil))
+        do {
+          try api.noop()
+          reply(wrapResult(nil))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       noopChannel.setMessageHandler(nil)
@@ -322,8 +333,12 @@
       echoAllTypesChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let everythingArg = args[0] as! AllTypes
-        let result = api.echo(everythingArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(everythingArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoAllTypesChannel.setMessageHandler(nil)
@@ -334,8 +349,12 @@
       echoAllNullableTypesChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let everythingArg = args[0] as? AllNullableTypes
-        let result = api.echo(everythingArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(everythingArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoAllNullableTypesChannel.setMessageHandler(nil)
@@ -344,8 +363,12 @@
     let throwErrorChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostIntegrationCoreApi.throwError", binaryMessenger: binaryMessenger, codec: codec)
     if let api = api {
       throwErrorChannel.setMessageHandler { _, reply in
-        api.throwError()
-        reply(wrapResult(nil))
+        do {
+          try api.throwError()
+          reply(wrapResult(nil))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       throwErrorChannel.setMessageHandler(nil)
@@ -356,8 +379,12 @@
       echoIntChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let anIntArg = args[0] as! Int32
-        let result = api.echo(anIntArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(anIntArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoIntChannel.setMessageHandler(nil)
@@ -368,8 +395,12 @@
       echoDoubleChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aDoubleArg = args[0] as! Double
-        let result = api.echo(aDoubleArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aDoubleArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoDoubleChannel.setMessageHandler(nil)
@@ -380,8 +411,12 @@
       echoBoolChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aBoolArg = args[0] as! Bool
-        let result = api.echo(aBoolArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aBoolArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoBoolChannel.setMessageHandler(nil)
@@ -392,8 +427,12 @@
       echoStringChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aStringArg = args[0] as! String
-        let result = api.echo(aStringArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aStringArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoStringChannel.setMessageHandler(nil)
@@ -404,8 +443,12 @@
       echoUint8ListChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aUint8ListArg = args[0] as! FlutterStandardTypedData
-        let result = api.echo(aUint8ListArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aUint8ListArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoUint8ListChannel.setMessageHandler(nil)
@@ -416,8 +459,12 @@
       echoObjectChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let anObjectArg = args[0]!
-        let result = api.echo(anObjectArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(anObjectArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoObjectChannel.setMessageHandler(nil)
@@ -429,8 +476,12 @@
       extractNestedNullableStringChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let wrapperArg = args[0] as! AllNullableTypesWrapper
-        let result = api.extractNestedNullableString(from: wrapperArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.extractNestedNullableString(from: wrapperArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       extractNestedNullableStringChannel.setMessageHandler(nil)
@@ -442,8 +493,12 @@
       createNestedNullableStringChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let nullableStringArg = args[0] as? String
-        let result = api.createNestedObject(with: nullableStringArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.createNestedObject(with: nullableStringArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       createNestedNullableStringChannel.setMessageHandler(nil)
@@ -456,8 +511,12 @@
         let aNullableBoolArg = args[0] as? Bool
         let aNullableIntArg = args[1] as? Int32
         let aNullableStringArg = args[2] as? String
-        let result = api.sendMultipleNullableTypes(aBool: aNullableBoolArg, anInt: aNullableIntArg, aString: aNullableStringArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.sendMultipleNullableTypes(aBool: aNullableBoolArg, anInt: aNullableIntArg, aString: aNullableStringArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       sendMultipleNullableTypesChannel.setMessageHandler(nil)
@@ -468,8 +527,12 @@
       echoNullableIntChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aNullableIntArg = args[0] as? Int32
-        let result = api.echo(aNullableIntArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aNullableIntArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoNullableIntChannel.setMessageHandler(nil)
@@ -480,8 +543,12 @@
       echoNullableDoubleChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aNullableDoubleArg = args[0] as? Double
-        let result = api.echo(aNullableDoubleArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aNullableDoubleArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoNullableDoubleChannel.setMessageHandler(nil)
@@ -492,8 +559,12 @@
       echoNullableBoolChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aNullableBoolArg = args[0] as? Bool
-        let result = api.echo(aNullableBoolArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aNullableBoolArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoNullableBoolChannel.setMessageHandler(nil)
@@ -504,8 +575,12 @@
       echoNullableStringChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aNullableStringArg = args[0] as? String
-        let result = api.echo(aNullableStringArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aNullableStringArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoNullableStringChannel.setMessageHandler(nil)
@@ -516,8 +591,12 @@
       echoNullableUint8ListChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aNullableUint8ListArg = args[0] as? FlutterStandardTypedData
-        let result = api.echo(aNullableUint8ListArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aNullableUint8ListArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoNullableUint8ListChannel.setMessageHandler(nil)
@@ -528,8 +607,12 @@
       echoNullableObjectChannel.setMessageHandler { message, reply in
         let args = message as! [Any?]
         let aNullableObjectArg = args[0]
-        let result = api.echo(aNullableObjectArg)
-        reply(wrapResult(result))
+        do {
+          let result = try api.echo(aNullableObjectArg)
+          reply(wrapResult(result))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       echoNullableObjectChannel.setMessageHandler(nil)
@@ -974,7 +1057,7 @@
 ///
 /// Generated protocol from Pigeon that represents a handler of messages from Flutter.
 protocol HostTrivialApi {
-  func noop()
+  func noop() throws
 }
 
 /// Generated setup class from Pigeon to handle messages through the `binaryMessenger`.
@@ -985,8 +1068,12 @@
     let noopChannel = FlutterBasicMessageChannel(name: "dev.flutter.pigeon.HostTrivialApi.noop", binaryMessenger: binaryMessenger)
     if let api = api {
       noopChannel.setMessageHandler { _, reply in
-        api.noop()
-        reply(wrapResult(nil))
+        do {
+          try api.noop()
+          reply(wrapResult(nil))
+        } catch {
+          reply(wrapError(error))
+        }
       }
     } else {
       noopChannel.setMessageHandler(nil)
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 4075a3d..c9c1144 100644
--- a/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift
+++ b/packages/pigeon/platform_tests/test_plugin/macos/Classes/TestPlugin.swift
@@ -34,9 +34,8 @@
     return everything
   }
 
-  func throwError() {
-    // TODO(stuartmorgan): Implement this. See
-    // https://github.com/flutter/flutter/issues/112483
+  func throwError() throws {
+    throw ErrType.thrownErrow
   }
 
   func echo(_ anInt: Int32) -> Int32 {
@@ -189,3 +188,7 @@
     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 85afe61..834fc0d 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.1), do not edit directly.
+// Autogenerated from Pigeon (v7.1.2), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 #undef _HAS_EXCEPTIONS
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 eab4bdd..081dd22 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.1), do not edit directly.
+// Autogenerated from Pigeon (v7.1.2), do not edit directly.
 // See also: https://pub.dev/packages/pigeon
 
 #ifndef PIGEON_CORE_TESTS_GEN_H_
diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml
index 351b71b..c535983 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.1 # This must match the version in lib/generator_tools.dart
+version: 7.1.2 # This must match the version in lib/generator_tools.dart
 
 environment:
   sdk: ">=2.12.0 <3.0.0"
diff --git a/packages/pigeon/test/swift_generator_test.dart b/packages/pigeon/test/swift_generator_test.dart
index 1618216..4f42a0f 100644
--- a/packages/pigeon/test/swift_generator_test.dart
+++ b/packages/pigeon/test/swift_generator_test.dart
@@ -340,8 +340,8 @@
     const SwiftGenerator generator = SwiftGenerator();
     generator.generate(swiftOptions, root, sink);
     final String code = sink.toString();
-    expect(code, contains('func doSomething() -> Output'));
-    expect(code, contains('let result = api.doSomething()'));
+    expect(code, contains('func doSomething() throws -> Output'));
+    expect(code, contains('let result = try api.doSomething()'));
     expect(code, contains('reply(wrapResult(result))'));
   });
 
@@ -737,8 +737,8 @@
     const SwiftGenerator generator = SwiftGenerator();
     generator.generate(swiftOptions, root, sink);
     final String code = sink.toString();
-    expect(code, contains('func doit() -> [Int32?]'));
-    expect(code, contains('let result = api.doit()'));
+    expect(code, contains('func doit() throws -> [Int32?]'));
+    expect(code, contains('let result = try api.doit()'));
     expect(code, contains('reply(wrapResult(result))'));
   });
 
@@ -795,11 +795,11 @@
     const SwiftGenerator generator = SwiftGenerator();
     generator.generate(swiftOptions, root, sink);
     final String code = sink.toString();
-    expect(code, contains('func add(x: Int32, y: Int32) -> Int32'));
+    expect(code, contains('func add(x: Int32, y: Int32) throws -> Int32'));
     expect(code, contains('let args = message as! [Any?]'));
     expect(code, contains('let xArg = args[0] as! Int32'));
     expect(code, contains('let yArg = args[1] as! Int32'));
-    expect(code, contains('let result = api.add(x: xArg, y: yArg)'));
+    expect(code, contains('let result = try api.add(x: xArg, y: yArg)'));
     expect(code, contains('reply(wrapResult(result))'));
   });
 
@@ -859,7 +859,7 @@
     const SwiftGenerator generator = SwiftGenerator();
     generator.generate(swiftOptions, root, sink);
     final String code = sink.toString();
-    expect(code, contains('func doit() -> Int32?'));
+    expect(code, contains('func doit() throws -> Int32?'));
   });
 
   test('return nullable host async', () {