Flutterfire: Bad state: Future already completed

Created on 21 Sep 2019  Â·  3Comments  Â·  Source: FirebaseExtended/flutterfire

When initilising remote config this error is thrown.

The code

remoteConfig = await RemoteConfig.instance;
            remoteConfig.setConfigSettings(RemoteConfigSettings(debugMode: true));
            await remoteConfig.fetch(expiration: const Duration(seconds: 1));
            await remoteConfig.activateFetched();
            String stingified = remoteConfig.getString("app_questions");

The Error

Bad state: Future already completed

Output Flutter -v:

✓] Flutter (Channel stable, v1.9.1+hotfix.2, on Mac OS X 10.14.6 18G95, locale en-GB)
    • Flutter version 1.9.1+hotfix.2 at /Users/earyzhe/dev/SDKs/flutter
    • Framework revision 2d2a1ffec9 (2 weeks ago), 2019-09-06 18:39:49 -0700
    • Engine revision b863200c37
    • Dart version 2.5.0


[✓] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    • Android SDK at /Users/earyzhe/Library/Android/sdk
    • Android NDK location not configured (optional; useful for native profiling support)
    • Platform android-28, build-tools 28.0.3
    • Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 11.0)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Xcode 11.0, Build version 11A420a
    • CocoaPods version 1.7.5

[✓] Android Studio (version 3.5)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin version 39.0.3
    • Dart plugin version 191.8423
    • Java version OpenJDK Runtime Environment (build 1.8.0_202-release-1483-b49-5587405)

[✓] IntelliJ IDEA Community Edition (version 2018.3.4)
    • IntelliJ at /Applications/IntelliJ IDEA CE.app
    • Flutter plugin version 33.2.2
    • Dart plugin version 183.5901

[✓] VS Code (version 1.38.1)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.4.1

[✓] Connected device (3 available)
    • Android SDK built for x86 • emulator-5556                            • android-x86 • Android 9 (API 28) (emulator)
    • Andrew's iPhone           • 6aa0c9719a85c174869a09656237b42f23701a91 • ios         • iOS 13.0
    • iPhone 11 Pro Max         • F7FDFDAF-B8D3-478B-AF97-927C3237EB43     • ios         • com.apple.CoreSimulator.SimRuntime.iOS-13-0 (simulator)

• No issues found!
customer remote_config bug

Most helpful comment

@earyzhe Is it possible that due to state changes in Flutter the code you sent gets executed twice shortly after each other? Or you call RemoteConfig.instance somewhere else at the same time?

This is what happened to me.

@kroikie @collinjackson There is a test to check for this use case: doubleInstance

What I've done:

  1. Clone flutterfire
  2. Checkout firebase_remote_config-v0.3.0+1
  3. Run cd packages/firebase_remote_config
  4. Run flutter pub get
  5. Run test flutter test --plain-name doubleInstance test/firebase_remote_config_test.dart
  6. See test fail with error:


Test result

> flutter test --plain-name doubleInstance test/firebase_remote_config_test.dart
00:03 +0 -1: RemoteConfig doubleInstance [E]                                                                                                                                                                                                
  Bad state: Future already completed
  dart:async                                                   _AsyncCompleter.complete
  package:firebase_remote_config/src/remote_config.dart 36:26  RemoteConfig.instance
  ===== asynchronous gap ===========================
  dart:async                                                   Future.wait
  test/firebase_remote_config_test.dart 62:14                  main.<fn>.<fn>
  dart:async                                                   _AsyncAwaitCompleter.start
  test/firebase_remote_config_test.dart 57:28                  main.<fn>.<fn>

00:03 +0 -1: Some tests failed.

Interestingly, if I run all tests using: flutter test test/firebase_remote_config_test.dart everything works as expected.

From my understanding of the code, this can be explained like this:

  1. Test instance starts to run to checks if the instance can be created.
    1.1. Test calls RemoteConfig.instance.
    1.2. By calling [1.1] the _instanceCompleter is now complete
    1.3. Because the _instanceCompleter property is static the state is preserved across tests and still is completed when...
  2. Test doubleInstance starts
    2.1. When RemoteConfig.instance gets called twice the both won't go into this line which causes the error as the _instanceCompleter is already completed from the previous test.
    2.2. None of the calls throw the StateError which occurs if the first two calls to RemoteConfig.instance happen at the same time.

From that, I went to make the tests independent from each other:
First I made _instanceCompleter visible for testing like this:

@visibleForTesting
static Completer<RemoteConfig> instanceCompleter = Completer<RemoteConfig>();

And added a teardown call to reset the instanceCompleter to the default value:

tearDown(() {
  RemoteConfig.instanceCompleter = Completer<RemoteConfig>();
});

Now the doubleInstance test fails as expected.

To fix the error itself, I added used try/catch around the instanceCompleter.complete() call and only ignore StateErrors with the message Future already completed.

I hope this is an acceptable solution to this problem.

I opened up a pull request to fix this bug and make the test behave as expected. #2061

All 3 comments

I reported this issue a while ago and opened a pull request to fix this issue. flutter/flutter#38060

@earyzhe Is it possible that due to state changes in Flutter the code you sent gets executed twice shortly after each other? Or you call RemoteConfig.instance somewhere else at the same time?

This is what happened to me.

@kroikie @collinjackson There is a test to check for this use case: doubleInstance

What I've done:

  1. Clone flutterfire
  2. Checkout firebase_remote_config-v0.3.0+1
  3. Run cd packages/firebase_remote_config
  4. Run flutter pub get
  5. Run test flutter test --plain-name doubleInstance test/firebase_remote_config_test.dart
  6. See test fail with error:


Test result

> flutter test --plain-name doubleInstance test/firebase_remote_config_test.dart
00:03 +0 -1: RemoteConfig doubleInstance [E]                                                                                                                                                                                                
  Bad state: Future already completed
  dart:async                                                   _AsyncCompleter.complete
  package:firebase_remote_config/src/remote_config.dart 36:26  RemoteConfig.instance
  ===== asynchronous gap ===========================
  dart:async                                                   Future.wait
  test/firebase_remote_config_test.dart 62:14                  main.<fn>.<fn>
  dart:async                                                   _AsyncAwaitCompleter.start
  test/firebase_remote_config_test.dart 57:28                  main.<fn>.<fn>

00:03 +0 -1: Some tests failed.

Interestingly, if I run all tests using: flutter test test/firebase_remote_config_test.dart everything works as expected.

From my understanding of the code, this can be explained like this:

  1. Test instance starts to run to checks if the instance can be created.
    1.1. Test calls RemoteConfig.instance.
    1.2. By calling [1.1] the _instanceCompleter is now complete
    1.3. Because the _instanceCompleter property is static the state is preserved across tests and still is completed when...
  2. Test doubleInstance starts
    2.1. When RemoteConfig.instance gets called twice the both won't go into this line which causes the error as the _instanceCompleter is already completed from the previous test.
    2.2. None of the calls throw the StateError which occurs if the first two calls to RemoteConfig.instance happen at the same time.

From that, I went to make the tests independent from each other:
First I made _instanceCompleter visible for testing like this:

@visibleForTesting
static Completer<RemoteConfig> instanceCompleter = Completer<RemoteConfig>();

And added a teardown call to reset the instanceCompleter to the default value:

tearDown(() {
  RemoteConfig.instanceCompleter = Completer<RemoteConfig>();
});

Now the doubleInstance test fails as expected.

To fix the error itself, I added used try/catch around the instanceCompleter.complete() call and only ignore StateErrors with the message Future already completed.

I hope this is an acceptable solution to this problem.

I opened up a pull request to fix this bug and make the test behave as expected. #2061

I'm having this issue outside test environment.
await RemoteConfig.instance is throwing Bad State: Future already completed always.
My code snippet:

          remoteConfig = await RemoteConfig.instance;
          await remoteConfig.fetch(expiration: const Duration(hours: 0));
          await remoteConfig.activateFetched();

My workaround was just to add try+catch and keep the flow going when the error is BadState: Future already completed

flutter doctor -v :
[✓] Flutter (Channel stable, v1.17.5, on Linux, locale pt_BR.UTF-8)
• Flutter version 1.17.5 at /home/leonardo/Documentos/devTools/flutter
• Framework revision 8af6b2f038 (5 weeks ago), 2020-06-30 12:53:55 -0700
• Engine revision ee76268252
• Dart version 2.8.4

[✓] Android toolchain - develop for Android devices (Android SDK version 29.0.3)
• Android SDK at /home/leonardo/Android/Sdk
• Platform android-29, build-tools 29.0.3
• Java binary at: /opt/android-studio/jre/bin/java
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)
• All Android licenses accepted.

[✓] Android Studio (version 4.0)
• Android Studio at /opt/android-studio
• Flutter plugin version 47.1.2
• Dart plugin version 193.7361
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6222593)

[✓] Connected device (1 available)
• moto g 7 play • 0056621193 • android-arm • Android 10 (API 29)

Was this page helpful?
0 / 5 - 0 ratings