Skip to content

[pigeon] event channels handle multiple instances flaking on Android since flutter/packages #13438 (MissingPluginException on cancel) #195804

Closed

Description

@elliette

Note: This flake is blocking the flutter → packages autoroller.

Since 2026-10-30, the Pigeon Android integration test event channels handle multiple instances fails often on Linux_android custom_package_tests, on both master and stable. It fails on unrelated PRs, on postsubmit, and on every recent Flutter roll (flutter/packages#13529, flutter/packages#13532, flutter/packages#13533), so it's blocking the autoroller.

The first failure was 23 minutes after flutter/packages#13438 ("[pigeon] Allow event channel unregistration") merged. That PR changed the Android test plugin to unregister one of the two event channels the test uses as soon as the stream ends.

Related: #179154 is about the same test, but with a different error (StateError: Cannot add new events after calling close, macOS Swift). That issue is older and much less frequent. This one looks like a new, separate regression.

Failure

Builder: Linux_android custom_package_tests master (also ... stable), step Run package tests|custom tests, package packages/pigeon, test file platform_tests/test_plugin/example/integration_test/test.dart.

══╡ EXCEPTION CAUGHT BY SERVICES LIBRARY ╞══════════════════════════════════════════════════════════
The following MissingPluginException was thrown while de-activating platform stream on channel
dev.flutter.pigeon.pigeon_integration_tests.EventChannelMethods.streamConsistentNumbers.1:
MissingPluginException(No implementation found for method cancel on channel
dev.flutter.pigeon.pigeon_integration_tests.EventChannelMethods.streamConsistentNumbers.1)

When the exception was thrown, this was the stack:
#0      MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:363:7)
<asynchronous suspension>
#1      EventChannel.receiveBroadcastStream.<anonymous closure> (package:flutter/src/services/platform_channel.dart:725:11)
<asynchronous suspension>
════════════════════════════════════════════════════════════════════════════════════════════════════
00:44 +678 -1: event channels handle multiple instances [E]
  Test failed. See exception logs above.

Likely cause

flutter/packages#13438 (merged 2026-10-30T14:38Z) changed
packages/pigeon/platform_tests/test_plugin/android/src/main/kotlin/com/example/test_plugin/TestPlugin.kt
so that it unregisters instance "1" as soon as that stream sends end-of-stream:

val streamHandlerOne = SendConsistentNumbers(1)
eventChannelOne =
    StreamConsistentNumbersStreamHandler.register(
        binding.binaryMessenger, streamHandlerOne, "1")
streamHandlerOne.onCompleted = { eventChannelOne?.setStreamHandler(null) }
if (count >= 10) {
  sink.endOfStream()
  onCompleted?.invoke()   // unregisters the channel right after endOfStream
}

When the Dart side receives end-of-stream, EventChannel.receiveBroadcastStream closes its controller. That runs onCancel, which calls invokeMethod('cancel') on the same channel. Whether that works depends on timing:

  • If cancel reaches the host before setStreamHandler(null) runs, it succeeds.
  • If cancel arrives after, no handler is registered. The call throws MissingPluginException, EventChannel reports it through FlutterError.reportError, and the test fails.

Only instance "1" (the one that gets unregistered) ever appears in the failures. That fits this explanation.

Evidence

The first matching failure is try build #26952, created 2026-10-30T15:01Z, after flutter/packages#13438 landed at 14:38Z. The scanned window, back to 2026-10-17, has no matches before that.

Linux_android custom_package_tests master (try)

13 of the 24 red builds in the last 400 (2026-10-17 to 2026-11-02) match. All of them are from 2026-10-30 or later.

Build Date Change
27013 2026-11-02 flutter/packages#13533 (roll)
27007 2026-11-02 flutter/packages#13532 (roll)
27006 2026-11-02 flutter/packages#13529 (roll)
26995 2026-11-02 flutter/packages#13253
26992 2026-11-02 flutter/packages#13253
26980 2026-10-31 flutter/packages#13265
26979 2026-10-31 flutter/packages#13342
26964 2026-10-30 flutter/packages#13492
26961 2026-10-30 flutter/packages#13505 (stable roll)
26958 2026-10-30 flutter/packages#13502 (roll)
26955 2026-10-30 flutter/packages#13501
26953 2026-10-30 flutter/packages#13500
26952 2026-10-30 flutter/packages#13499

Linux_android custom_package_tests master (prod / postsubmit)

4 of the 19 red builds in the last 300 (2026-09-23 to 2026-11-01) match:

  • #4074, 2026-10-30, commit f3f97373c
  • #4082, #4083, #4084, 2026-11-01, commit 3f34a6f7a. All three Cocoon retries failed.

Linux_android custom_package_tests stable (try)

2 of the 10 red builds match: #26818 (2026-10-30, flutter/packages#13499) and #26844 (2026-10-31, flutter/packages#13342).

It also fails on stable, so this isn't a Flutter SDK regression. The problem is in flutter/packages code.

Possible fixes

  1. Unregister after the Dart side cancels, not after end-of-stream. For example, call setStreamHandler(null) from SendConsistentNumbers.onCancel instead of right after sink.endOfStream(). Dart always sends cancel after it receives end-of-stream, so the unregister would happen after that call has been handled.
  2. Revert the TestPlugin.kt part of [pigeon] Allow event channel unregistration packages#13438 (keep the generator changes) until the test is reworked.
  3. If unregistering before cancel is meant to be a supported pattern for users of the new API, this test may be showing a real usability problem. It could be worth documenting, or handling in the generated setStreamHandler(null) path.

Activity

  1. added
    p: pigeonrelated to pigeon messaging codegen tool
    P1High-priority issues at the top of the work list
    c: flakeTests that sometimes, but not always, incorrectly pass
    on Nov 2, 2026
  2. changed the title [-][pigeon] `event channels handle multiple instances` flaking on Android since #13438 (MissingPluginException on `cancel`)[/-] [+][pigeon] `event channels handle multiple instances` flaking on Android since flutter/packages #13438 (MissingPluginException on `cancel`)[/+] on Nov 2, 2026
  3. elliette commented on Nov 2, 2026

    @elliette
    MemberAuthor

    flutter/packages#13528 was just merged/ It changes the Kotlin and Swift test plugins to unregister channel "1" from the stream handler's onCancel, instead of right after endOfStream(). The handler now stays registered until the Dart side's cancel call has been received, which removes the race described above.

    I'm going to close this issue as fixed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1High-priority issues at the top of the work listc: flakeTests that sometimes, but not always, incorrectly passp: pigeonrelated to pigeon messaging codegen toolteam-ecosystemOwned by Ecosystem team

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions