Skip to content

#167410: _initCalled completed twice#9694

Merged
auto-submit[bot] merged 16 commits intoflutter:mainfrom
srivats22:167410
Feb 19, 2026
Merged

#167410: _initCalled completed twice#9694
auto-submit[bot] merged 16 commits intoflutter:mainfrom
srivats22:167410

Conversation

@srivats22
Copy link
Contributor

This PR Fixes: flutter/flutter#167410, where _initCalled was being performed twice on the web

Based on the discussion comments I have removed the calles to _initCalled in the google_sign_in_web package

Pre-Review Checklist

If you need help, consider asking for advice on the #hackers-new channel on Discord.

Note: The Flutter team is currently trialing the use of Gemini Code Assist for GitHub. Comments from the gemini-code-assist bot should not be taken as authoritative feedback from the Flutter team. If you find its comments useful you can update your code accordingly, but if you are unsure or disagree with the feedback, please feel free to wait for a Flutter team member's review for guidance on which automated comments should be addressed.

Footnotes

  1. Regular contributors who have demonstrated familiarity with the repository guidelines only need to comment if the PR is not auto-exempted by repo tooling. 2 3

@srivats22 srivats22 requested a review from ditman as a code owner July 29, 2025 15:15
@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests or get an explicit test exemption before merging.

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.If you believe this PR qualifies for a test exemption, contact "@test-exemption-reviewer" in the #hackers channel in Discord (don't just cc them here, they won't see it!). The test exemption team is a small volunteer group, so all reviewers should feel empowered to ask for tests, without delegating that responsibility entirely to the test exemption group.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

The pull request removes the _initCalled completer, which introduces a race condition. The init method should be made idempotent to handle being called multiple times. The CHANGELOG.md entry should be a complete sentence ending with a period.

@stuartmorgan-g stuartmorgan-g self-requested a review July 29, 2025 18:23
@srivats22
Copy link
Contributor Author

srivats22 commented Jul 29, 2025

Hi,

any idea or pointers on how to fix this:

The following TestFailure was thrown running a test (but after
the test had completed):
Expected: throws <Instance of 'StateError'>
  Actual: <Closure: () => Future<Null> from: () => {
                            let t$goto = 0, t$completer =
async._makeAsyncAwaitCompleter(T.Null());
                            var t$36asyncBody =
async._wrapJsFunctionForAsync((t$errorCode, t$result) => {
                              if (t$errorCode === 1) return
async._asyncRethrow(t$result, t$completer);
                              while (true)
                                switch (t$goto) {
                                  case 0:
                                    // Function start
                                    t$goto = 2;
                                    return
async._asyncAwait(t$36$35plugin$35get().disconnect(C[8] ||
CT.C8), t$36asyncBody, t$completer);
                                  case 2:
                                    // returning from await.
                                    // implicit return
                                    return
async._asyncReturn(null, t$completer);
                                }
                            });
                            return
async._asyncStartSync(t$36asyncBody, t$completer);
                          }>
   Which: returned a Future that emitted <null>

When the exception was thrown, this was the stack:

its failing for the same reason in 3 of the tests and the repo check I know the issue which I will fix...

@stuartmorgan-g
Copy link
Collaborator

I'm not sure I understand the question. The expectations that check that calling a method without calling init throws a StateError are failing because you removed the code that throws the StateError if a method is called without calling init.

@srivats22
Copy link
Contributor Author

Oh so the changes in the PR is incorrect? Or something else needs to change?

@stuartmorgan-g
Copy link
Collaborator

Tests that expect that the web implementation asserts init completion everywhere are no longer valid if the web implementation no longer asserts init completion. Intentional behavioral changes often require changing tests.

@srivats22
Copy link
Contributor Author

Understood let me look at the code and see where the initCompleted is still be called in the test and remove those... Last I checked wasn't able to find any

@stuartmorgan-g
Copy link
Collaborator

From triage: Is this ready for review?

@srivats22
Copy link
Contributor Author

Yes its ready for review looks like I might need to fix the conflicts which I will get to

@stuartmorgan-g stuartmorgan-g added the triage-web Should be looked at in web triage label Aug 19, 2025
@mdebbar mdebbar requested review from mdebbar and removed request for ditman August 20, 2025 18:15
Copy link
Contributor

@mdebbar mdebbar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for contributing this fix!

Some thoughts:

When the app calls init() twice (potentially with different params), it becomes a tricky situation. We already have the first init() in flight while the second init() is being executed.

I think we should let both init() calls continue to completion. Any calls to await initialized; should await the latest init() call.

init(InitParameters(clientId: 111));
init(InitParameters(clientId: 222));
await initialized;
// At this point, the plugin should be ready with clientId 222.

@stuartmorgan-g what do other platforms do in this case?

@srivats22
Copy link
Contributor Author

I made the changes based on what was put in the issue... What I got from it was since the logic has been moved outside the package the code for init seems redundant... I might have miss understood let me take a look based on the comments and try and incorporate it

@stuartmorgan-g
Copy link
Collaborator

stuartmorgan-g commented Aug 21, 2025

@stuartmorgan-g what do other platforms do in this case?

Nothing; in the new version of google_sign_in, clients explicitly call an initialize method (rather than it being an internal, implicit thing on most platforms, but semi-exposed on web, as was the case before), and the docs say they must do so exactly once. It's a programming error by the client to write the code you've shown there.

If we think clients need explicit Errors when doing the wrong thing, that should be added to the app-facing package, rather than handled in each implementation. This code is a legacy of the exposed-for-web nature of the previous init code.

(Also, clients should basically never call the platform interface methods directly. That's not how most federated plugins are designed.)

@@ -1,3 +1,7 @@
## 1.0.1

* Fixes Bad state: Future already completed on the web.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds like there was a bug in the plugin that was fixed, which is not the case. This should say something like "Removes initialization checks, since initialization handling has moved to the app-facing package."

/// This ensures that the SDK has been loaded, and that the `init` method
/// has finished running.
@visibleForTesting
Future<void> get initialized {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should just be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will work on it and push the updated changes by today if possible

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removing the function completely won't work cause the renderButton uses the initialized function as the future

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That code is wrong now though; initialized is now equivalent to just _jsSdkLoadedFuture in this PR, but the code in renderButton that is being guarded requires _gisSdkClient to be non-null, and there's no order guarantee between those two things.

If we want to keep renderButton callable before initialization (I'm skeptical that that's actually important with the new API structure), then the internals need to be restructured to make that actually work. But that can be done with an internal future that doesn't have a getter wrapping it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood so how should I proceed??

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mdebbar Do you want renderButton to be callable before the plugin client has run initialize at the app-facing package level?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From triage: Ping @mdebbar on the question above.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at iOS and Android implementations and I didn't see explicit errors being thrown if init() is called twice.

The documentation says: or calling this method more than once, will result in undefined behavior. I would say throwing an error qualifies as "undefined behavior" :)

Here's my suggestion:

  1. Make initialized a private property _initialized to be used by methods in this file, and returned from init() to be used by users.
  2. Throw if init() is called more than once.
  3. _gisSdkClient should become late final GisSdkClient _gisSdkClient; so that it can only be set once, and it throws if accessed before initialization.

Copy link
Contributor

@mdebbar mdebbar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the delay in my response. I gave this some more thought and looked at the documentation and other platforms. See my suggestion in the comment below.

/// This ensures that the SDK has been loaded, and that the `init` method
/// has finished running.
@visibleForTesting
Future<void> get initialized {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at iOS and Android implementations and I didn't see explicit errors being thrown if init() is called twice.

The documentation says: or calling this method more than once, will result in undefined behavior. I would say throwing an error qualifies as "undefined behavior" :)

Here's my suggestion:

  1. Make initialized a private property _initialized to be used by methods in this file, and returned from init() to be used by users.
  2. Throw if init() is called more than once.
  3. _gisSdkClient should become late final GisSdkClient _gisSdkClient; so that it can only be set once, and it throws if accessed before initialization.

@srivats22
Copy link
Contributor Author

srivats22 commented Oct 27, 2025

Thank you, I will work on it with the directions provided and update the PR

@stuartmorgan-g
Copy link
Collaborator

From triage: What is the status of this PR? It looks like there are still CI failures that need to be addressed.

@srivats22
Copy link
Contributor Author

From triage: What is the status of this PR? It looks like there are still CI failures that need to be addressed.

I tried fixing it based on the failures but it kept comming back not sure what needs to change

@stuartmorgan-g
Copy link
Collaborator

Have you run the integration test with the debugger to find out which expectation is failing?

@srivats22
Copy link
Contributor Author

I did let me try it again and see

@srivats22
Copy link
Contributor Author

I looked at the errors again

The Linux repo checks failed cause the change log was not correct but I addressed that

the others are failing cause of this:
Unhandled exception:
DriverError: Error while reading FlutterDriver result for command: window.$flutterDriver('{"command":"request_data","timeout":"1200000"}')
Original error: Expected: not null
Actual:

not sure how to proceed

@stuartmorgan-g
Copy link
Collaborator

not sure how to proceed

Have you tried running that failing integration test under the debugger, with breakpoints, to find out where exactly the test expectation is failing, as I suggested in my previous comment?

@srivats22
Copy link
Contributor Author

srivats22 commented Jan 6, 2026

not sure how to proceed

Have you tried running that failing integration test under the debugger, with breakpoints, to find out where exactly the test expectation is failing, as I suggested in my previous comment?

I have been pasting the below command into my terminal and been running it

dart run script/tool/bin/flutter_plugin_tools.dart drive-examples --packages=google_sign_in/google_sign_in_web --web

and then it runs but gets stuck after sometime

Am i suppose to be running it differently?

@srivats22
Copy link
Contributor Author

All tests have passed sorry for the delay...

Copy link
Contributor

@mdebbar mdebbar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thanks for your patience until we got it right :)

@mdebbar
Copy link
Contributor

mdebbar commented Feb 18, 2026

From web triage: @stuartmorgan-g would you be able to take a final look?

@stuartmorgan-g stuartmorgan-g added autosubmit Merge PR when tree becomes green via auto submit App and removed triage-web Should be looked at in web triage labels Feb 19, 2026
@auto-submit auto-submit bot merged commit 5c8ab99 into flutter:main Feb 19, 2026
81 checks passed
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Feb 20, 2026
mdebbar added a commit that referenced this pull request Feb 20, 2026
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Feb 20, 2026
auto-submit bot pushed a commit that referenced this pull request Feb 20, 2026
## Reason for revert:
The PR being reverted (#9694) caused a bug in `renderButton`: flutter/flutter#182633
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Feb 23, 2026
github-merge-queue bot pushed a commit to flutter/flutter that referenced this pull request Feb 23, 2026
flutter/packages@9da22bf...12b43a1

2026-02-20 rick.hohler@gmail.com [webview_flutter_wkwebview] Fix crash
when calling setOnConsoleMessage multiple times (flutter/packages#10922)
2026-02-20 engine-flutter-autoroll@skia.org Manual roll Flutter from
c023e5b to 91b2d41 (31 revisions) (flutter/packages#11088)
2026-02-20 kallentu@google.com [rfw] Remove old TODOs for code block
languages. (flutter/packages#11080)
2026-02-20 matt.boetger@gmail.com [google_maps_flutter] Remove
usesCleartextTraffic (flutter/packages#11079)
2026-02-20 stuartmorgan@google.com [google_maps_flutter] Improve iOS
shared code validation (flutter/packages#11070)
2026-02-20 mdebbar@google.com Revert "#167410: _initCalled completed
twice (#9694)" (flutter/packages#11084)
2026-02-20 49699333+dependabot[bot]@users.noreply.github.com
[dependabot]: Bump androidx.activity:activity from 1.12.2 to 1.12.4 in
/packages/image_picker/image_picker_android/android
(flutter/packages#11033)
2026-02-20 matt.boetger@gmail.com [interactive_media_ads] Remove
usesCleartextTraffic (flutter/packages#11065)
2026-02-19 matt.boetger@gmail.com [image_picker] Remove
usesCleartextTraffic (flutter/packages#11076)
2026-02-19 matt.boetger@gmail.com [quick_actions_android] Remove
deprecated usesCleartextTraffic (flutter/packages#11063)
2026-02-19 matt.boetger@gmail.com [quick_actions] Remove
usesCleartextTraffic (flutter/packages#11064)
2026-02-19 matt.boetger@gmail.com [google_maps_flutter_android] Remove
usesCleartextTraffic (flutter/packages#11078)
2026-02-19 louisehsu@google.com [google_maps_flutter_ios] Migrate to
UIScene (flutter/packages#11001)
2026-02-19 matt.boetger@gmail.com [image_picker_android] Remove
deprecated usesCleartextTraffic (flutter/packages#11059)
2026-02-19 matt.boetger@gmail.com [file_selector_android] Remove
deprecated usesCleartextTraffic (flutter/packages#11057)
2026-02-19 matt.boetger@gmail.com [webview_flutter_android] Remove
usesCleartextTraffic (flutter/packages#11066)
2026-02-19 49699333+dependabot[bot]@users.noreply.github.com
[dependabot]: Bump exoplayer_version from 1.9.1 to 1.9.2 in
/packages/video_player/video_player_android/android
(flutter/packages#10985)
2026-02-19 stuartmorgan@google.com [google_maps_flutter] Fix add-marker
crash on Android (flutter/packages#11061)
2026-02-19 42980667+srivats22@users.noreply.github.com #167410:
_initCalled completed twice (flutter/packages#9694)

If this roll has caused a breakage, revert this CL and stop the roller
using the controls here:
https://autoroll.skia.org/r/flutter-packages-flutter-autoroll
Please CC flutter-ecosystem@google.com on the revert to ensure that a
human
is aware of the problem.

To file a bug in Flutter:
https://github.com/flutter/flutter/issues/new/choose

To report a problem with the AutoRoller itself, please file a bug:
https://issues.skia.org/issues/new?component=1389291&template=1850622

Documentation for the AutoRoller is here:
https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autosubmit Merge PR when tree becomes green via auto submit App p: google_sign_in platform-web

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[google_sign_in_web] _initCalled completed twice

3 participants