Skip to content

[web] Stale web_plugin_registrant.dart reused when plugin set changes — newly added plugins silently never register in built apps #189128

Description

@forTheSakeOfLogic

Steps to reproduce

The whole reproduction is five CLI commands from a fresh flutter create — no project download needed:

flutter create --platforms web repro && cd repro

# 1. Start with any web-enabled plugin and build once.
flutter pub add url_launcher
flutter build web --release

# 2. Add a second plugin, exactly like a project evolving over time.
flutter pub add package_info_plus

# 3. Build again — same command, same machine, no clean in between.
flutter build web --release

# 4. Inspect the registrant the build just compiled:
grep registerWith .dart_tool/flutter_build/*/web_plugin_registrant.dart

Actual result (after step 3 — the second build "succeeds"):

  UrlLauncherPlugin.registerWith(registrar);

PackageInfoPlusWebPlugin.registerWith(...) is missing. The generated web_plugin_registrant.dart was not regenerated when the plugin set changed; the build directory (same hash, e.g. .dart_tool/flutter_build/522e0d9d…) was reused with the stale file, and the stale registrant is what gets compiled into main.dart.js. The newly added plugin's web implementation silently never registers in the shipped app.

Expected result:

  PackageInfoPlusWebPlugin.registerWith(registrar);
  UrlLauncherPlugin.registerWith(registrar);

which is exactly what you get after flutter clean && flutter build web --release.

The loud inverse variant (proves the staleness directly)

Going the other direction fails loudly instead of silently. In a project that has built web release with N plugins, remove a plugin from pubspec.yaml, flutter pub get, and rebuild:

Target dart2js failed: …
.dart_tool/flutter_build/<hash>/web_plugin_registrant.dart:15:8:
Error: Not found: 'package:package_info_plus/src/package_info_plus_web.dart'

The build tries to compile the stale registrant, which still imports the removed package. Same root cause, opposite symptom: the registrant target is not invalidated when the plugin set changes (as long as both states have ≥ 1 plugin, so the build-directory hash stays the same — going from zero plugins to some plugins changes the hash and regenerates correctly, which is why single-shot fresh repros never catch this).

How this bites in production (real-world impact)

We hit this in a real app and it was brutal to diagnose:

  • The app used Firebase (web) and was developed for weeks with flutter run -d chrome — debug is unaffected (different build pipeline/artifacts), so everything worked daily.

  • The first-ever flutter build web --release + deploy produced a blank white screen. The project's long-lived .dart_tool still contained registrants generated before the Firebase plugins were added (we later found multiple stale web_plugin_registrant.dart files from different eras of the project sitting in different flutter_build/<hash>/ dirs).

  • With no FirebaseCoreWeb registered, FirebasePlatform.instance silently fell back to the method-channel default and Firebase.initializeApp() threw:

    PlatformException(channel-error, Unable to establish connection on channel:
    "dev.flutter.pigeon.firebase_core_platform_interface.FirebaseCoreHostApi.initializeCore")
    

    which killed main() before runApp → pure white page. In minified release the console shows only a bare "Uncaught ", so we had to attach CDP to extract the Dart exception.

  • The misdirection potential is extreme: flutter build web --profile of the same tree worked (different build args → different flutter_build/<hash> dir → freshly generated registrant), which made it look like a dart2js/minification bug. Checking out an older commit into a fresh worktree also "worked" (clean dir), which made it look like a recently-added package was the culprit. Both were red herrings — it was the stale registrant all along.

  • Existing reports of channel-error …initializeCore are all mobile-native registration problems; we found no issue describing this web build-cache mechanism, and searching for the actual cause is nearly impossible from the symptom.

Anyone with a long-lived checkout who added a web-relevant plugin after their first web build, and whose CI/dev flow doesn't happen to run flutter clean, can ship an app with silently unregistered plugins (MissingPluginException / channel-error / features no-oping at runtime).

Workarounds

  • flutter clean before release web builds (or delete .dart_tool/flutter_build), or
  • register web plugin implementations explicitly in main() via a conditional-import shim that mirrors the generated registrant (registering twice is harmless).

Expected behaviour

flutter build web should regenerate (or invalidate) web_plugin_registrant.dart whenever the resolved plugin set changes — plugin additions/removals in pubspec.yaml must be part of the fingerprint that decides whether the registrant (and the kernel/dart2js outputs that depend on it) are up to date.

Flutter Doctor output

flutter doctor -v
[✓] Flutter (Channel stable, 3.41.9, on macOS 26.5.1 25F80 darwin-arm64, locale en-CA)
    • Flutter version 3.41.9 on channel stable at /Users/…/flutter
    • Framework revision 00b0c91f06 (2026-04-29)
    • Engine revision 42d3d75a56
    • Dart version 3.11.5
    • DevTools version 2.54.2
Dart SDK version: 3.11.5 (stable)

Reproduced with flutter build web --release (also applies with default args; debug flutter run is unaffected; --profile appeared unaffected only because the different args select a different cached build directory).


Transparency note: this bug was diagnosed and this report was written by Claude (Anthropic's Fable 5 model) working in Claude Code, at the request and with the permission of this account's owner, who asked that the investigation be credited accurately. Happy to provide any additional detail from the diagnostic session (CDP traces, the stale registrant files from the affected project, etc.) via the account owner.

Activity

  1. forTheSakeOfLogic commented on Jul 8, 2026

    @forTheSakeOfLogic
    Author

    Prior-art survey (searched GitHub, StackOverflow, and the wider web for earlier reports of this mechanism):

    • Regenerate Dart plugin registrant after a hot restart #76219 (2021, P1, closed) is the closest precedent: the same class of staleness — plugin registrant not regenerated after a pubspec.yaml plugin change — was reported and fixed for the hot-restart path back then. This issue is the same failure class surviving in the flutter build web path: the registrant target is not invalidated when the plugin set changes between two non-empty states.
    • [Bug]:  fluttercommunity/plus_plugins#1976 (2023, closed) appears to be a wild sighting of the loud variant of this bug: after upgrading package_info_plus past the version where the separate package_info_plus_web package was discontinued, the user's flutter build web --release failed compiling a .dart_tool/flutter_build/<hash>/web_plugin_registrant.dart that still imported the discontinued package_info_plus_web — i.e., a stale registrant from before the upgrade. It was closed as a user import error, but the offending import is in the generated file, and flutter clean would have "fixed" it — consistent with the mechanism described here.
    • StackOverflow currently has no questions mentioning web_plugin_registrant at all; the symptoms appear to get absorbed by generic "run flutter clean" folklore without the tool bug being identified, which is likely why the silent add-a-plugin variant hasn't been reported until now.
  2. suryaKommana2662 commented on Jul 9, 2026

    @suryaKommana2662

    @forTheSakeOfLogic Thank you for this exceptionally high-quality and thorough bug report. Providing a 5-command reproduction case makes it very easy to verify.

    I have reproduced the issue and confirmed that the build-cache fingerprinting logic in flutter_tools is failing to invalidate the stale registrant file. I am labeling and routing this to the team-tool to investigate.

  3. added
    toolAffects the "flutter" command-line tool. See also t: labels.
    platform-webWeb applications specifically
    team-toolOwned by Flutter Tool team
    a: buildBuilding flutter applications with the tool
    fyi-webFor the attention of Web platform team
    and removed
    in triagePresently being triaged by the triage team
    on Jul 9, 2026
  4. added
    P2Important issues not at the top of the work list
    triaged-toolTriaged by Flutter Tool team
    on Jul 14, 2026
  5. self-assigned this
    on Jul 14, 2026
  6. github-actions commented on Aug 6, 2026

    @github-actions

    This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.

  7. locked as resolved and limited conversation to collaborators on Aug 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

P2Important issues not at the top of the work lista: buildBuilding flutter applications with the toolfyi-webFor the attention of Web platform teamplatform-webWeb applications specificallyteam-toolOwned by Flutter Tool teamtoolAffects the "flutter" command-line tool. See also t: labels.triaged-toolTriaged by Flutter Tool team

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions