Skip to content

web: skwasm (--wasm) silently fails to render async-appended platform-view content under real GPU acceleration #193223

Closed

Description

@0danylo

Summary

With a flutter build web --wasm (skwasm) build, an HtmlElementView whose platform-view factory returns an empty container div — into which content (a real third-party <iframe>) is appended later, after an async gap — silently fails to ever show that content when the page is running under real GPU-accelerated rendering. No console error, no exception, nothing in Network — the container div exists, but stays empty forever. The exact same build works correctly when Chrome is forced to --disable-gpu (software rendering), which is what makes this easy to miss in CI/headless testing that defaults to software rendering.

Concretely, this breaks Google Identity Services' "Sign in with Google" button (google_identity_services_web's gis.id.renderButton(), which injects Google's own iframe into a container Element you hand it) — but the underlying issue looks like a skwasm platform-view compositing bug, not something specific to that package.

Environment

Flutter 3.47.1 • channel stable
Framework revision 6655482ec0 (2026-08-19)
Engine revision 5d5317886
Tools Dart 3.13.1
  • Platform: web, --wasm (skwasm renderer)
  • Reproduces in headless Chromium (--headless=new) only with real GPU acceleration enabled (--use-gl=angle --use-angle=gl --enable-gpu-rasterization --ignore-gpu-blocklist). Does not reproduce with --disable-gpu (software/Skia CPU fallback) — that's the part that makes it easy to miss.
  • Reproduces identically whether skwasm is running single-threaded (the default, no cross-origin isolation) or genuinely multi-threaded (page served with Cross-Origin-Opener-Policy: same-origin + Cross-Origin-Embedder-Policy: require-corp, confirmed via crossOriginIsolated === true and the single-threaded-fallback console warning disappearing). So it isn't specific to the single-threaded fallback path either.

What's affected in the real app

google_identity_services_web's GSI button, rendered via roughly this pattern (trimmed from the actual widget):

class _GoogleSignInButtonState extends State<_GoogleSignInButton> {
  final _containerReady = Completer<web.Element>();

  @override
  void initState() {
    super.initState();
    ui_web.platformViewRegistry.registerViewFactory(_viewType, (int viewId) {
      final container = web.document.createElement('div');
      container.setAttribute('style', 'width: 100%; height: 100%; ...');
      _containerReady.complete(container);
      return container;
    });

    Future.wait([_ensureGisScriptLoaded(), _containerReady.future]).then((results) {
      final container = results[1] as web.Element;
      gis.id.renderButton(container, gis.GsiButtonConfiguration(/* ... */));
    });
  }

  @override
  Widget build(BuildContext context) => HtmlElementView(viewType: _viewType);
}

On production (a real, deployed Flutter web app built with --wasm), this container's div is created and reachable in the DOM, google.accounts.id loads successfully, renderButton() is called with no thrown error — but document.querySelectorAll('iframe[src*="accounts.google.com"]').length is 0 afterward, and the button is visibly just empty space. Same build, same page, --disable-gpu: the iframe appears correctly (length: 1), button renders and is clickable.

What I ruled out

Trying to narrow this to a minimal reproduction, all of the following work correctly (real GPU, same Flutter version, same --wasm build):

  1. A bare HtmlElementView whose factory returns a real <iframe> directly (synchronously, no async gap).
  2. The same, but the factory returns an empty container div and an iframe is appended into it after an await Future.delayed(...) — matching the real code's two-phase container-then-content shape.
  3. The real google_identity_services_web package, real gis.id.renderButton() call, real Google client ID, against https://accounts.google.com/gsi/client for real — in a fresh, otherwise-empty flutter create project.
  4. All of the above wrapped in SelectionArea (desktop web's SelectableRegion wraps platform views in its own Stack/HtmlElementView, which has separately-documented layout-timing issues, so this seemed like a plausible interaction) at a desktop-sized viewport (1400×1000) — still renders fine.

So this doesn't appear to be the platform-view mechanism alone, google_identity_services_web alone, or SelectionArea alone — something about the surrounding app (larger widget tree / more concurrent platform views or semantics work / navigation-triggered mount rather than initial-load mount / something else not yet isolated) is a necessary ingredient, and I wasn't able to isolate it further before filing this. Happy to help narrow it down further if it'd help — a maintainer with skwasm rendering-pipeline context probably has a much better idea where to look than blind bisection from the outside.

Reproducing

I have a real, currently-broken deployment I can point a maintainer at privately, and can capture a full trace, screen recording, or a minimal standalone project on request — didn't want to drop a live link to a business deployment straight into a public issue without being asked for one. Ping me here and I'll follow up with whatever's most useful.

Impact

This silently and completely breaks the only sign-in method on the affected page for any real (GPU-accelerated) browser — no error surfaces to the user or to error-tracking (Sentry, in our case), since nothing throws. We've reverted off --wasm in production because of this. Flagging the severity since "the primary CTA on the page silently does nothing, with zero diagnostic signal" seems like a bad failure mode for skwasm's platform-view compositing generally, beyond just this one widget.

Activity

  1. added
    platform-webWeb applications specifically
    needs repro infoAutomated crash report whose cause isn't yet known
    in triagePresently being triaged by the triage team
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    and removed
    in triagePresently being triaged by the triage team
    on Sep 23, 2026
  2. mbcorona commented on Sep 23, 2026

    @mbcorona
    Member

    Hi @0danylo, thanks for the report.

    Could you share a standalone minimal project that reproduces it, or a captured trace plus the private deployment link you offered?

  3. added
    e: web_skwasmSkwasm rendering backend for web
    engineflutter/engine related. See also e: labels.
    on Sep 23, 2026
  4. 0danylo commented on Sep 24, 2026

    @0danylo
    Author

    Hi, I checked the actual DOM and there is exactly one flt-platform-view host in the whole document, and it belongs to SelectableRegion's own internal context menu view, not the Google Sign In button view. The app wraps its whole desktop layout in SelectionArea, which is why that internal platform view exists on this screen at all.

    A full document search for the button's container div, matched by the distinctive inline style its own registerViewFactory callback sets (overflow: hidden plus justify-content: center, unique to this widget), finds zero matches anywhere on the page. The container the app creates for the button never gets attached to the DOM.

    Also zero network requests to accounts.google.com/gsi/button are ever issued, and there are no console errors or exceptions the whole time. renderButton() presumably never gets a real attached container to work with, and Google's SDK does not throw when that happens. It just does nothing visible.

    So when the widget tree has both an app registered HtmlElementView platform view and SelectableRegion's own internal platform view, only one platform view slot ends up attached to the document, and the other is dropped rather than composited incorrectly.

    One more thing: I tried an isolated repro with the real Google Identity Services button plus SelectionArea at desktop width, and it did not reproduce this failure on its own. So this looks necessary but not sufficient by itself. Something about the full app (more platform views elsewhere, timing, or something else I have not isolated) still seems to matter. I do not have a minimal standalone repro yet, just this stronger diagnosis from the real app.

    I also sent the site link to the email found on your profile, [email protected].

  5. removed
    waiting for responseThe Flutter team cannot make further progress on this issue until the original reporter responds
    on Sep 24, 2026
  6. kevmoo commented on Sep 24, 2026

    @kevmoo
    Contributor

    I'm throwing some tokens at this. Stay tuned...

  7. self-assigned this
    on Sep 24, 2026
  8. kevmoo commented on Sep 24, 2026

    @kevmoo
    Contributor

    Thanks for the detailed report — the "exactly one flt-platform-view" detail was the key clue. I was able to reproduce this on master (3.49.0-1.0.pre) with a small app.

    What's happening

    With the Chrome flags you listed (--use-gl=angle --use-angle=gl --enable-gpu-rasterization --ignore-gpu-blocklist) on a machine without a working native GL driver, Chrome's GPU process fails after the first WebGL context, and skwasm's own WebGL2 context creation fails. When that happens skwasm logs a single console.log line — Failed to create context! — and then never finishes initializing its surface. Every frame waits on that forever:

    • nothing is actually painted (the page has no rendering canvas),
    • platform views that are part of the first frame (e.g. SelectionArea's internal context-menu view) still get their flt-platform-view injected, because injection happens before the wait,
    • platform views mounted later (e.g. your sign-in button after navigation) are never injected — which is why the GSI container was never attached and no request to accounts.google.com/gsi/button was made,
    • no exception is thrown.

    This also explains why your isolated repros "worked": if the button is in the first frame, its container is attached (so an iframe-count check passes), even though nothing is visibly rendered. --disable-gpu works because Chrome then uses SwiftShader for WebGL2, which succeeds.

    CanvasKit handles the same failure by falling back to CPU rendering (WARNING: Falling back to CPU-only rendering. Reason: failed to create GrContext.); skwasm has no such fallback.

    Questions

    1. On the real (non-headless) browsers where you saw this in production, does the console contain Failed to create context!? (It's a plain log line, not an error.)
    2. If so, could you share chrome://gpu from one of those machines (especially the WebGL2 / GPU process lines)?

    If the answer to (1) is no, the production failure is likely a different issue and we should track it separately.

    Fix in progress: #193293 (draft) makes skwasm report the context-creation failure and surface a clear error instead of hanging silently. Note this turns the silent hang into a visible error; it doesn't make rendering work when WebGL2 is unavailable.

  9. 0danylo commented on Sep 24, 2026

    @0danylo
    Author

    answer to (1) is no, there's basically nothing in console:

    Unchecked runtime.lastError: The message port closed before a response was received.

    flutter_bootstrap.js:2 Flutter Web: Skwasm uses multi-threading and web workers for better performance, but your page needs to be cross-origin isolated to support multi-threading. Skwasm will run in single-threaded mode.
    To enable multithreading, serve your app with these HTTP response headers:
    Cross-Origin-Opener-Policy: same-origin
    Cross-Origin-Embedder-Policy: require-corp
    See https://web.dev/articles/coop-coep for guidance.
    To silence this warning, set suppressMultithreadingWarning: true in your Flutter configuration.

  10. kevmoo commented on Sep 24, 2026

    @kevmoo
    Contributor

    Thanks! That rules out the WebGL context failure for your production case. #193293 still fixes the headless-with-GPU-flags hang, but what your users hit is something else. A few things would help narrow it down:

    1. Verbose console output. In DevTools, open the console's log-level dropdown, enable Verbose, reload, and navigate to the page with the button. Some platform-view failures are only logged at console.debug, which Chrome hides by default. Please paste anything that shows up.
    2. Does the rest of the UI keep updating? After navigating to the page where the button should appear, do other widgets still repaint normally (animations, hover effects, text input, navigating away and back)? Or does the app look frozen? This tells us whether rendering has stalled or only the platform view is being dropped.
    3. What sits above the button in the widget tree? Please list any BackdropFilter, ImageFiltered, Opacity/AnimatedOpacity, Transform/scale animations, ClipRect/ClipRRect, or custom page transitions between the route and the HtmlElementView. Also, does the button's parent give it a non-zero size?

    Also useful: the exact Flutter version you build production with (flutter --version), and whether the same build on CanvasKit (flutter build web without --wasm) works on the same machines.

  11. 0danylo commented on Sep 24, 2026

    @0danylo
    Author
    1. Unchecked runtime.lastError: The message port closed before a response was received.
      flutter_bootstrap.js:2 Flutter Web: Skwasm uses multi-threading and web workers for better performance, but your page needs to be cross-origin isolated to support multi-threading. Skwasm will run in single-threaded mode.
      To enable multithreading, serve your app with these HTTP response headers:
      Cross-Origin-Opener-Policy: same-origin
      Cross-Origin-Embedder-Policy: require-corp
      See https://web.dev/articles/coop-coep for guidance.
      To silence this warning, set suppressMultithreadingWarning: true in your Flutter configuration.
      U @ flutter_bootstrap.js:2
      await in U
      load @ flutter_bootstrap.js:35
      await in load
      (anonymous) @ flutter_bootstrap.js:42
      main.dart.mjs:817 TrustedTypes available. Creating policy: gis-dart
      main.dart.mjs:277 [Violation] 'setTimeout' handler took 70ms
      main.dart.mjs:277 [Violation] 'setTimeout' handler took 121ms
      5[Violation] 'requestAnimationFrame' handler took ms
      skwasm.js:32 [Violation] 'requestAnimationFrame' handler took 72ms
      skwasm.js:32 [Violation] 'requestAnimationFrame' handler took 162ms
      main.dart.mjs:295 [Violation] 'requestAnimationFrame' handler took 98ms
      main.dart.mjs:295 [Violation] 'requestAnimationFrame' handler took 55ms
      skwasm.js:32 [Violation] 'requestAnimationFrame' handler took 51ms

    2. yes, no other problems on the page, including a scrolling animation

    FocusTraversalGroup → MaterialApp.router → builder: Overlay → OverlayEntry → OpineSelectionArea → (desktop) SelectionArea → GoRouter's Navigator → SignInScreen → Scaffold → SafeArea → LayoutBuilder →
    SingleChildScrollView → ConstrainedBox → Padding → Align → ConstrainedBox(maxWidth:640) → Column →
    _SignInButtons → Column → Center → SizedBox(height:44, width:340) → _GoogleSignInButton → Stack →
    HtmlElementView

    BackdropFilter/ImageFiltered: none anywhere in this chain.

    Opacity/AnimatedOpacity/Transform: no true ancestor has one. There is an AnimatedOpacity in _GoogleSignInButton.build(), but it's a sibling in the Stack, not a wrapper, it's Google's own white pill placeholder that fades from opaque to opacity: 0 once _rendered flips true. Since gis.id.renderButton() never throws even when the platform view failed to attach (confirmed earlier this session), _rendered gets set regardless of whether anything actually painted, so this fade-out completing is not evidence the button worked, it just means the code thinks it did. No page-transition Transform/Fade either: app_router.dart has no custom pageTransitionsTheme or CustomTransitionPage, so it's Flutter's default, which only wraps the page during the ~300ms navigation animation, not persistently.

    ClipRect/ClipRRect: SingleChildScrollView defaults to Clip.hardEdge, and Stack's default clipBehavior is also Clip.hardEdge since Flutter 3.3ish. Neither should clip the button away since it sits fully inside both, but they're real clips in the chain, worth naming since you asked for a complete list.

    Non-zero parent size: yes, explicit SizedBox(height: 44, width: 340) wrapped in Center, confirmed hardcoded, not computed from intrinsic content.

    The one real finding: SelectionArea genuinely sits as an ancestor of everything, including this button, not a sibling. And SelectionArea's own internal PlatformSelectableRegionContextMenu is itself a Stack over its own HtmlElementView, per the doc comment in opine_selection_area.dart:74-84. So the tree literally contains two platform views in an ancestor/descendant relationship: SelectionArea's own platform view wrapping the whole page, and the sign-in button's platform view nested inside it. That matches our earlier DOM finding (only one flt-platform-view slot ever attaches) more precisely than "sibling" did, worth telling him it's a true ancestor relationship, not two independent views.

    Also: Flutter version: Flutter 3.47.1 • channel stable, revision 6655482, engine hash
    11d79658c444477b06513d32b52c8c4ccb7276b0, Dart 3.13.1. It works normally without WASM. on the broken site, document.querySelectorAll('[id*=gsi]') returns nothing at all, not hidden, not zero-size, just absent from the DOM. The registerViewFactory that creates that div is never invoked.

  12. kevmoo commented on Sep 24, 2026

    @kevmoo
    Contributor

    Thank you, this is really helpful, and it rules out several theories.

    One detail I'd like to pin down with actual logging, since it changes where we look. You mentioned the registerViewFactory callback is never invoked, but also that renderButton() runs and _rendered flips to true. renderButton() needs the element that the factory returns. Also, document.querySelectorAll(...) only finds elements that are attached to the document. So "factory never ran" and "factory ran, but its div was never attached to the page" look the same from DevTools.

    Could you add some temporary logging along these lines? Plain print is fine: it goes to the browser console in release --wasm builds too.

    import 'dart:ui_web' as ui_web;
    import 'package:web/web.dart' as web;
    
    // Wherever you register the factory today:
    ui_web.platformViewRegistry.registerViewFactory(viewType, (int viewId) {
      final div = /* your existing element creation */;
      print('[gsi-debug] factory invoked, viewId=$viewId');
      web.console.log(div); // live element: right-click → "Reveal in Elements panel"
      Future<void>.delayed(const Duration(seconds: 3), () {
        print('[gsi-debug] 3s later: viewId=$viewId isConnected=${div.isConnected}');
      });
      return div;
    });
    print('[gsi-debug] registered $viewType');
    
    // And on the widget:
    HtmlElementView(
      viewType: viewType,
      onPlatformViewCreated: (int id) => print('[gsi-debug] onPlatformViewCreated id=$id'),
    )

    On a working build (I checked this snippet locally with skwasm), you get all four lines and isConnected=true. What I'd like to know from the broken site:

    • Which [gsi-debug] lines appear at all.
    • Whether isConnected is true or false.
    • What document.querySelectorAll('flt-platform-view').length returns after navigating to the sign-in screen.

    Two more questions about production:

    1. Which browsers/OS/devices do you see this on? All users on --wasm, or a subset (e.g. certain GPUs, Linux, VMs/remote desktops)?
    2. Does it reproduce for you in your own everyday desktop Chrome (no special flags), or only in the headless/automated setup?

    Thanks again for sticking with this!

  13. 0danylo commented on Sep 24, 2026

    @0danylo
    Author

    Of course, I'd also like to get this figured out.

    I ran the instrumented build on staging. None of the four debug lines showed up, not even registered $viewType, which is the first line and runs synchronously in initState() before any async work starts. No exceptions either, checked Runtime.exceptionThrown and Log.entryAdded at every level, nothing beyond the usual skwasm single-threaded warning. So it's not that the factory ran and the div never got attached. initState() for that widget never runs at all, and nothing throws to explain why.

    DOM state after navigating to the sign-in screen: flt-platform-view count is 1 (SelectionArea's own), zero elements match [id*=gsi].

    For your questions:

    1. Works on Firefox on two different machines, RTX 3050 laptop on Ubuntu and RTX 2070 desktop on Windows 10 and on Brave mobile on an iPhone 17. Does not work on Brave desktop, on either of those same two machines. The second user who confirmed it also saw it fail, but I don't know their browser or OS.
    2. Yes. This is what I see day to day on my own desktop Brave (Chromium based), no special flags, nothing headless. Same failure as the automated setup.

    New stuff: same GPU vendor (Nvidia) on both machines, same desktop layout and SelectionArea wrapping on both, and Firefox works while Brave doesn't. That seems like something Brave desktop specific rather than GPU/skwasm in general. Shields being down and trying a guest profile (all defaults) didn't fix it, so it's probably not ad/tracker blocking or extensions. Brave also randomizes WebGL/canvas output by default as anti-fingerprinting ("farbling"), separate from Shields, and I don't know if that's disabled by the same per-site Shields toggle or not. If skwasm's WebGL2 context setup is sensitive to that, it could explain a browser-specific failure.

  14. kevmoo commented on Sep 24, 2026

    @kevmoo
    Contributor

    Thanks, this narrows it down a lot.

    If initState() for the button widget never runs, the engine's platform-view code isn't involved yet. The engine only gets involved once the widget is built and the framework sends the create message. So something above _GoogleSignInButton is not building it on Brave desktop. The rest of the UI renders and animates, so skwasm's WebGL context is working there. Brave's WebGL/canvas farbling changes the values pages read back; it shouldn't prevent a widget from being built.

    A few things would help us tell whether this is Chromium-wide, Brave-specific, or specific to --wasm:

    1. Plain Google Chrome on one of the failing machines (same --wasm build): does it work?

    2. The same app built without --wasm, opened in Brave desktop: does it work? (Earlier "works without WASM" — was that in Brave?)

    3. One level up. Please move the prints to the parent that decides whether to show the Google button (_SignInButtons.build, plus whatever condition, FutureBuilder or state flag gates _GoogleSignInButton). If the button waits on a Future, e.g. GIS SDK loading (loadWebSdk() / GoogleSignIn.instance.initialize()), please print before and after that await:

      print('[gsi-debug] before GIS init');
      await /* your GIS / google_sign_in init call */;
      print('[gsi-debug] after GIS init');

      The GIS loader completes when the SDK script calls window.onGoogleLibraryLoad. If that script is blocked or never finishes loading, the Future never completes and nothing throws, which matches what you're seeing.

    4. In Brave's Network tab: what's the status of the request to https://accounts.google.com/gsi/client? And in the console, what does typeof google?.accounts?.id return on the sign-in screen?

  15. 0danylo commented on Sep 24, 2026

    @0danylo
    Author

    Moved the prints up as you asked, redeployed, confirmed the live bundle's main.dart.wasm md5 matches the local build so this isn't stale.

    _SignInButtons.build fires, kIsWeb=true, so it enters the branch that should build the button. buildGoogleSignInButton called never prints. The call inside that branch never happens. initState() still never runs either. No exception anywhere, checked Runtime.exceptionThrown and Log.entryAdded at every level again. The GIS SDK itself loads fine independently of our button: the request to accounts.google.com/gsi/client returns 200, and typeof google.accounts.id is "object" on the sign-in screen.

    For your other questions, tested directly on the two failing machines:

    1. Plain Chrome, same --wasm build: fails, same as Brave. Also tested Edge on the same build: fails too.
    2. Same app without --wasm (production), opened in Brave desktop: works.

    So it's not Brave. Firefox works on both machines on the --wasm build, and Chrome, Edge, and Brave all fail on it, on the same hardware. Brave without --wasm works. This looks like Chromium/Blink plus --wasm, not any one browser's features.

  16. kevmoo commented on Sep 25, 2026

    @kevmoo
    Contributor

    Thanks, that's the key data point. I think I know what's going on.

    Firefox doesn't actually run the wasm build. Flutter's loader only enables dart2wasm/skwasm on Chromium browsers by default (defaultWasmSupport is blink: true, gecko: false, webkit: false in flutter.js). Firefox and iOS browsers silently fall back to the main.dart.js build that flutter build web --wasm also produces. So the pattern isn't "Chromium vs. Firefox". It's wasm fails, JS works, everywhere.

    "Branch entered, but the call never happens, and no exception" points to a conditional import. Under dart2wasm, dart:html, dart:js and dart:js_util don't exist, so conditional imports keyed on them pick the stub file. I checked this locally with the same four conditions in one app:

    condition --wasm (skwasm) JS build
    dart.library.html stub web
    dart.library.js stub web
    dart.library.js_util stub web
    dart.library.js_interop web web

    If buildGoogleSignInButton comes from something like

    import 'google_button_stub.dart'
        if (dart.library.html) 'google_button_web.dart';

    then the wasm build calls the stub version. The stub typically returns SizedBox.shrink() / Container(), and it doesn't contain your print. That would look exactly like "the call never happens": no platform view, no exception, and initState() never runs.

    Could you check how buildGoogleSignInButton (and anything else web-specific) is imported? If it's keyed on dart.library.html, dart.library.js, or dart.library.js_util, switching the condition to dart.library.js_interop should fix it. A quick way to confirm first is a print inside the stub's version of the function.

    (The skwasm hang I found earlier with the headless GPU flags is a real, separate bug; #193293 still addresses that.)

  17. 0danylo commented on Sep 27, 2026

    @0danylo
    Author

    That's it!! Checked the actual import:

    export 'stub.dart' if (dart.library.js_util) 'web.dart';

    stub.dart returns const SizedBox.shrink();, matches your prediction.

    Grepped the rest of the codebase for the same pattern and found six more files with the identical if (dart.library.js_util) condition, covering back/forward-cache reload, user agent detection, a tab title badge, referrer tracking, a pending-vote-through-sign-in mechanism, and a reload-on-update prompt. All seven pick their non-web stub under --wasm, none of them error. Fixing the condition to dart.library.js_interop across all seven fixes the problem and I can use WASM now.

    Appreciate you sticking with this. Thanks!

  18. github-actions commented on Oct 11, 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.

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

Metadata

Metadata

Assignees

Labels

e: web_skwasmSkwasm rendering backend for webengineflutter/engine related. See also e: labels.needs repro infoAutomated crash report whose cause isn't yet knownplatform-webWeb applications specifically

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions