[pigeon] Fix Kotlin generator to use provided errorClassName (#5480)

Fix bug with Pigeon Kotlin code generator not using the provided `errorClassName`.

fixes: https://github.com/flutter/flutter/issues/139031

*If you had to change anything in the [flutter/tests] repo, include a link to the migration guide as per the [breaking change policy].*
diff --git a/packages/pigeon/CHANGELOG.md b/packages/pigeon/CHANGELOG.md
index 501f6c8..f317a24 100644
--- a/packages/pigeon/CHANGELOG.md
+++ b/packages/pigeon/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 15.0.0
+
+* **Breaking Change** [kotlin] Updates Flutter API to use new errorClassName.
+
 ## 14.0.1
 
 * Updates minimum supported SDK version to Flutter 3.10/Dart 3.0.
diff --git a/packages/pigeon/lib/generator_tools.dart b/packages/pigeon/lib/generator_tools.dart
index 608ba53..342800d 100644
--- a/packages/pigeon/lib/generator_tools.dart
+++ b/packages/pigeon/lib/generator_tools.dart
@@ -13,7 +13,7 @@
 /// The current version of pigeon.
 ///
 /// This must match the version in pubspec.yaml.
-const String pigeonVersion = '14.0.1';
+const String pigeonVersion = '15.0.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 e8d69eb..88ffb48 100644
--- a/packages/pigeon/lib/kotlin_generator.dart
+++ b/packages/pigeon/lib/kotlin_generator.dart
@@ -358,6 +358,7 @@
         });
       });
 
+      final String errorClassName = _getErrorClassName(generatorOptions);
       for (final Method func in api.methods) {
         final String returnType = func.returnType.isVoid
             ? 'Unit'
@@ -396,12 +397,12 @@
             indent.writeScoped('if (it is List<*>) {', '} ', () {
               indent.writeScoped('if (it.size > 1) {', '} ', () {
                 indent.writeln(
-                    'callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))');
+                    'callback(Result.failure($errorClassName(it[0] as String, it[1] as String, it[2] as String?)))');
               }, addTrailingNewline: false);
               if (!func.returnType.isNullable && !func.returnType.isVoid) {
                 indent.addScoped('else if (it[0] == null) {', '} ', () {
                   indent.writeln(
-                      'callback(Result.failure(FlutterError("null-error", "Flutter api returned null value for non-null return value.", "")))');
+                      'callback(Result.failure($errorClassName("null-error", "Flutter api returned null value for non-null return value.", "")))');
                 }, addTrailingNewline: false);
               }
               indent.addScoped('else {', '}', () {
@@ -681,8 +682,8 @@
     indent.newln();
     indent.write('private fun wrapError(exception: Throwable): List<Any?> ');
     indent.addScoped('{', '}', () {
-      indent.write(
-          'if (exception is ${generatorOptions.errorClassName ?? "FlutterError"}) ');
+      indent
+          .write('if (exception is ${_getErrorClassName(generatorOptions)}) ');
       indent.addScoped('{', '}', () {
         indent.write('return ');
         indent.addScoped('listOf(', ')', () {
@@ -713,7 +714,7 @@
     indent.writeln(
         ' * @property details The error details. Must be a datatype supported by the api codec.');
     indent.writeln(' */');
-    indent.write('class ${generatorOptions.errorClassName ?? "FlutterError"} ');
+    indent.write('class ${_getErrorClassName(generatorOptions)} ');
     indent.addScoped('(', ')', () {
       indent.writeln('val code: String,');
       indent.writeln('override val message: String? = null,');
@@ -722,13 +723,15 @@
     indent.addln(' : Throwable()');
   }
 
-  void _writeCreateConnectionError(Indent indent) {
+  void _writeCreateConnectionError(
+      KotlinOptions generatorOptions, Indent indent) {
+    final String errorClassName = _getErrorClassName(generatorOptions);
     indent.newln();
     indent.write(
-        'private fun createConnectionError(channelName: String): FlutterError ');
+        'private fun createConnectionError(channelName: String): $errorClassName ');
     indent.addScoped('{', '}', () {
       indent.write(
-          'return FlutterError("channel-error",  "Unable to establish connection on channel: \'\$channelName\'.", "")');
+          'return $errorClassName("channel-error",  "Unable to establish connection on channel: \'\$channelName\'.", "")');
     });
   }
 
@@ -749,7 +752,7 @@
       _writeWrapError(generatorOptions, indent);
     }
     if (hasFlutterApi) {
-      _writeCreateConnectionError(indent);
+      _writeCreateConnectionError(generatorOptions, indent);
     }
     _writeErrorClass(generatorOptions, indent);
   }
@@ -763,6 +766,9 @@
 /// Calculates the name of the codec that will be generated for [api].
 String _getCodecName(Api api) => '${api.name}Codec';
 
+String _getErrorClassName(KotlinOptions generatorOptions) =>
+    generatorOptions.errorClassName ?? 'FlutterError';
+
 String _getArgumentName(int count, NamedType argument) =>
     argument.name.isEmpty ? 'arg$count' : argument.name;
 
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 e1c371c..798d668 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
@@ -20,7 +20,7 @@
 }
 
 private fun wrapError(exception: Throwable): List<Any?> {
-  if (exception is FlutterError) {
+  if (exception is CoreTestsError) {
     return listOf(exception.code, exception.message, exception.details)
   } else {
     return listOf(
@@ -30,8 +30,8 @@
   }
 }
 
-private fun createConnectionError(channelName: String): FlutterError {
-  return FlutterError(
+private fun createConnectionError(channelName: String): CoreTestsError {
+  return CoreTestsError(
       "channel-error", "Unable to establish connection on channel: '$channelName'.", "")
 }
 
@@ -42,7 +42,7 @@
  * @property message The error message.
  * @property details The error details. Must be a datatype supported by the api codec.
  */
-class FlutterError(
+class CoreTestsError(
     val code: String,
     override val message: String? = null,
     val details: Any? = null
@@ -2397,7 +2397,8 @@
     channel.send(null) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else {
           callback(Result.success(Unit))
         }
@@ -2414,7 +2415,8 @@
     channel.send(null) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else {
           val output = it[0]
           callback(Result.success(output))
@@ -2432,7 +2434,8 @@
     channel.send(null) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else {
           callback(Result.success(Unit))
         }
@@ -2449,11 +2452,12 @@
     channel.send(listOf(everythingArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else if (it[0] == null) {
           callback(
               Result.failure(
-                  FlutterError(
+                  CoreTestsError(
                       "null-error",
                       "Flutter api returned null value for non-null return value.",
                       "")))
@@ -2477,7 +2481,8 @@
     channel.send(listOf(everythingArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else {
           val output = it[0] as AllNullableTypes?
           callback(Result.success(output))
@@ -2504,11 +2509,12 @@
     channel.send(listOf(aNullableBoolArg, aNullableIntArg, aNullableStringArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else if (it[0] == null) {
           callback(
               Result.failure(
-                  FlutterError(
+                  CoreTestsError(
                       "null-error",
                       "Flutter api returned null value for non-null return value.",
                       "")))
@@ -2529,11 +2535,12 @@
     channel.send(listOf(aBoolArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else if (it[0] == null) {
           callback(
               Result.failure(
-                  FlutterError(
+                  CoreTestsError(
                       "null-error",
                       "Flutter api returned null value for non-null return value.",
                       "")))
@@ -2554,11 +2561,12 @@
     channel.send(listOf(anIntArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else if (it[0] == null) {
           callback(
               Result.failure(
-                  FlutterError(
+                  CoreTestsError(
                       "null-error",
                       "Flutter api returned null value for non-null return value.",
                       "")))
@@ -2579,11 +2587,12 @@
     channel.send(listOf(aDoubleArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else if (it[0] == null) {
           callback(
               Result.failure(
-                  FlutterError(
+                  CoreTestsError(
                       "null-error",
                       "Flutter api returned null value for non-null return value.",
                       "")))
@@ -2604,11 +2613,12 @@
     channel.send(listOf(aStringArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else if (it[0] == null) {
           callback(
               Result.failure(
-                  FlutterError(
+                  CoreTestsError(
                       "null-error",
                       "Flutter api returned null value for non-null return value.",
                       "")))
@@ -2629,11 +2639,12 @@
     channel.send(listOf(aListArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else if (it[0] == null) {
           callback(
               Result.failure(
-                  FlutterError(
+                  CoreTestsError(
                       "null-error",
                       "Flutter api returned null value for non-null return value.",
                       "")))
@@ -2654,11 +2665,12 @@
     channel.send(listOf(aListArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else if (it[0] == null) {
           callback(
               Result.failure(
-                  FlutterError(
+                  CoreTestsError(
                       "null-error",
                       "Flutter api returned null value for non-null return value.",
                       "")))
@@ -2679,11 +2691,12 @@
     channel.send(listOf(aMapArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else if (it[0] == null) {
           callback(
               Result.failure(
-                  FlutterError(
+                  CoreTestsError(
                       "null-error",
                       "Flutter api returned null value for non-null return value.",
                       "")))
@@ -2704,11 +2717,12 @@
     channel.send(listOf(anEnumArg.raw)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else if (it[0] == null) {
           callback(
               Result.failure(
-                  FlutterError(
+                  CoreTestsError(
                       "null-error",
                       "Flutter api returned null value for non-null return value.",
                       "")))
@@ -2729,7 +2743,8 @@
     channel.send(listOf(aBoolArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else {
           val output = it[0] as Boolean?
           callback(Result.success(output))
@@ -2747,7 +2762,8 @@
     channel.send(listOf(anIntArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else {
           val output = it[0].let { if (it is Int) it.toLong() else it as Long? }
           callback(Result.success(output))
@@ -2765,7 +2781,8 @@
     channel.send(listOf(aDoubleArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else {
           val output = it[0] as Double?
           callback(Result.success(output))
@@ -2783,7 +2800,8 @@
     channel.send(listOf(aStringArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else {
           val output = it[0] as String?
           callback(Result.success(output))
@@ -2801,7 +2819,8 @@
     channel.send(listOf(aListArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else {
           val output = it[0] as ByteArray?
           callback(Result.success(output))
@@ -2819,7 +2838,8 @@
     channel.send(listOf(aListArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else {
           val output = it[0] as List<Any?>?
           callback(Result.success(output))
@@ -2840,7 +2860,8 @@
     channel.send(listOf(aMapArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else {
           val output = it[0] as Map<String?, Any?>?
           callback(Result.success(output))
@@ -2858,7 +2879,8 @@
     channel.send(listOf(anEnumArg?.raw)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else {
           val output = (it[0] as Int?)?.let { AnEnum.ofRaw(it) }
           callback(Result.success(output))
@@ -2879,7 +2901,8 @@
     channel.send(null) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else {
           callback(Result.success(Unit))
         }
@@ -2896,11 +2919,12 @@
     channel.send(listOf(aStringArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else if (it[0] == null) {
           callback(
               Result.failure(
-                  FlutterError(
+                  CoreTestsError(
                       "null-error",
                       "Flutter api returned null value for non-null return value.",
                       "")))
@@ -3057,11 +3081,12 @@
     channel.send(listOf(msgArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else if (it[0] == null) {
           callback(
               Result.failure(
-                  FlutterError(
+                  CoreTestsError(
                       "null-error",
                       "Flutter api returned null value for non-null return value.",
                       "")))
@@ -3081,11 +3106,12 @@
     channel.send(listOf(aStringArg)) {
       if (it is List<*>) {
         if (it.size > 1) {
-          callback(Result.failure(FlutterError(it[0] as String, it[1] as String, it[2] as String?)))
+          callback(
+              Result.failure(CoreTestsError(it[0] as String, it[1] as String, it[2] as String?)))
         } else if (it[0] == null) {
           callback(
               Result.failure(
-                  FlutterError(
+                  CoreTestsError(
                       "null-error",
                       "Flutter api returned null value for non-null return value.",
                       "")))
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 8b4e8bc..c14f712 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
@@ -39,7 +39,7 @@
   }
 
   override fun throwFlutterError(): Any? {
-    throw FlutterError("code", "message", "details")
+    throw CoreTestsError("code", "message", "details")
   }
 
   override fun echoInt(anInt: Long): Long {
@@ -170,7 +170,7 @@
   }
 
   override fun throwAsyncFlutterError(callback: (Result<Any?>) -> Unit) {
-    callback(Result.failure(FlutterError("code", "message", "details")))
+    callback(Result.failure(CoreTestsError("code", "message", "details")))
   }
 
   override fun echoAsyncAllTypes(everything: AllTypes, callback: (Result<AllTypes>) -> Unit) {
diff --git a/packages/pigeon/pubspec.yaml b/packages/pigeon/pubspec.yaml
index 2504ce1..f36d47a 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%3A%22p%3A+pigeon%22
-version: 14.0.1 # This must match the version in lib/generator_tools.dart
+version: 15.0.0 # This must match the version in lib/generator_tools.dart
 
 environment:
   sdk: ">=3.0.0 <4.0.0"
diff --git a/packages/pigeon/test/kotlin_generator_test.dart b/packages/pigeon/test/kotlin_generator_test.dart
index 606f47e..f51c68b 100644
--- a/packages/pigeon/test/kotlin_generator_test.dart
+++ b/packages/pigeon/test/kotlin_generator_test.dart
@@ -1635,4 +1635,166 @@
         contains(
             'callback(Result.failure(createConnectionError(channelName)))'));
   });
+
+  test('gen host uses default error class', () {
+    final Root root = Root(
+      apis: <Api>[
+        Api(
+          name: 'Api',
+          location: ApiLocation.host,
+          methods: <Method>[
+            Method(
+              name: 'method',
+              returnType: const TypeDeclaration.voidDeclaration(),
+              parameters: <Parameter>[
+                Parameter(
+                  name: 'field',
+                  type: const TypeDeclaration(
+                    baseName: 'int',
+                    isNullable: true,
+                  ),
+                ),
+              ],
+            )
+          ],
+        )
+      ],
+      classes: <Class>[],
+      enums: <Enum>[],
+    );
+    final StringBuffer sink = StringBuffer();
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    const KotlinGenerator generator = KotlinGenerator();
+    generator.generate(
+      kotlinOptions,
+      root,
+      sink,
+      dartPackageName: DEFAULT_PACKAGE_NAME,
+    );
+    final String code = sink.toString();
+    expect(code, contains('FlutterError'));
+  });
+
+  test('gen flutter uses default error class', () {
+    final Root root = Root(
+      apis: <Api>[
+        Api(
+          name: 'Api',
+          location: ApiLocation.flutter,
+          methods: <Method>[
+            Method(
+              name: 'method',
+              returnType: const TypeDeclaration.voidDeclaration(),
+              parameters: <Parameter>[
+                Parameter(
+                  name: 'field',
+                  type: const TypeDeclaration(
+                    baseName: 'int',
+                    isNullable: true,
+                  ),
+                ),
+              ],
+            )
+          ],
+        )
+      ],
+      classes: <Class>[],
+      enums: <Enum>[],
+    );
+    final StringBuffer sink = StringBuffer();
+    const KotlinOptions kotlinOptions = KotlinOptions();
+    const KotlinGenerator generator = KotlinGenerator();
+    generator.generate(
+      kotlinOptions,
+      root,
+      sink,
+      dartPackageName: DEFAULT_PACKAGE_NAME,
+    );
+    final String code = sink.toString();
+    expect(code, contains('FlutterError'));
+  });
+
+  test('gen host uses error class', () {
+    final Root root = Root(
+      apis: <Api>[
+        Api(
+          name: 'Api',
+          location: ApiLocation.host,
+          methods: <Method>[
+            Method(
+              name: 'method',
+              returnType: const TypeDeclaration.voidDeclaration(),
+              parameters: <Parameter>[
+                Parameter(
+                  name: 'field',
+                  type: const TypeDeclaration(
+                    baseName: 'int',
+                    isNullable: true,
+                  ),
+                ),
+              ],
+            )
+          ],
+        )
+      ],
+      classes: <Class>[],
+      enums: <Enum>[],
+    );
+    final StringBuffer sink = StringBuffer();
+    const String errorClassName = 'FooError';
+    const KotlinOptions kotlinOptions =
+        KotlinOptions(errorClassName: errorClassName);
+    const KotlinGenerator generator = KotlinGenerator();
+    generator.generate(
+      kotlinOptions,
+      root,
+      sink,
+      dartPackageName: DEFAULT_PACKAGE_NAME,
+    );
+    final String code = sink.toString();
+    expect(code, contains(errorClassName));
+    expect(code, isNot(contains('FlutterError')));
+  });
+
+  test('gen flutter uses error class', () {
+    final Root root = Root(
+      apis: <Api>[
+        Api(
+          name: 'Api',
+          location: ApiLocation.flutter,
+          methods: <Method>[
+            Method(
+              name: 'method',
+              returnType: const TypeDeclaration.voidDeclaration(),
+              parameters: <Parameter>[
+                Parameter(
+                  name: 'field',
+                  type: const TypeDeclaration(
+                    baseName: 'int',
+                    isNullable: true,
+                  ),
+                ),
+              ],
+            )
+          ],
+        )
+      ],
+      classes: <Class>[],
+      enums: <Enum>[],
+    );
+    final StringBuffer sink = StringBuffer();
+    const String errorClassName = 'FooError';
+    const KotlinOptions kotlinOptions =
+        KotlinOptions(errorClassName: errorClassName);
+    const KotlinGenerator generator = KotlinGenerator();
+    generator.generate(
+      kotlinOptions,
+      root,
+      sink,
+      dartPackageName: DEFAULT_PACKAGE_NAME,
+    );
+    final String code = sink.toString();
+    expect(code, contains(errorClassName));
+    expect(code, isNot(contains('FlutterError')));
+  });
 }
diff --git a/packages/pigeon/tool/shared/generation.dart b/packages/pigeon/tool/shared/generation.dart
index 00ec45b..1ae5a45 100644
--- a/packages/pigeon/tool/shared/generation.dart
+++ b/packages/pigeon/tool/shared/generation.dart
@@ -89,8 +89,7 @@
           ? null
           : '$outputBase/android/src/main/kotlin/com/example/test_plugin/$pascalCaseName.gen.kt',
       kotlinPackage: 'com.example.test_plugin',
-      kotlinErrorClassName:
-          input == 'core_tests' ? null : '${pascalCaseName}Error',
+      kotlinErrorClassName: '${pascalCaseName}Error',
       // iOS
       swiftOut: skipLanguages.contains(GeneratorLanguages.swift)
           ? null