amplify-flutter icon indicating copy to clipboard operation
amplify-flutter copied to clipboard

UninitializedPropertyAccessException crash on Android when amplify_datastore is included but not used

Open giulitu95 opened this issue 8 months ago • 13 comments

Description

We're observing a crash on Android devices only (iOS is unaffected) when the amplify_datastore package is included in the project, but no Amplify functionality is used at runtime.

In our case, we temporarily released our app without using any Amplify features, although the library was still present in pubspec.yaml.

This results in a runtime crash due to an uninitialized lateinit property, even though the plugin is never used or initialized in code.

Root cause

The issue originates from the DataStoreHubEventStreamHandler.kt file:

  • The token variable is declared as lateinit:

https://github.com/aws-amplify/amplify-flutter/blob/1b9155e24130efdb6c42cb8822c2c2da52b3149f/packages/amplify_datastore/android/src/main/kotlin/com/amazonaws/amplify/amplify_datastore/DataStoreHubEventStreamHandler.kt#L36

  • It is accessed in the onCancel() method:

https://github.com/aws-amplify/amplify-flutter/blob/1b9155e24130efdb6c42cb8822c2c2da52b3149f/packages/amplify_datastore/android/src/main/kotlin/com/amazonaws/amplify/amplify_datastore/DataStoreHubEventStreamHandler.kt#L224-L227

This method gets triggered by the Flutter engine even though the stream wasn't properly initialized — because no Amplify plugin was ever added or configured.

More specifically, the stream gets initialized only when the AmplifyDataStore plugin is added via Amplify.addPlugin(...), which internally sets up the static streamWrapper and assigns a DataStoreStreamController. When this step is skipped (as in our case), the token remains uninitialized, and accessing it during onCancel() causes the app to crash.

Expected behavior

Including the amplify_datastore package without using it should not crash the app. The plugin should:

  • Either check whether token is initialized using ::token.isInitialized before accessing it.

  • Or register/deregister the EventChannel only when the plugin is fully configured.

Sentry stacktrace

java.lang.RuntimeException: Unable to destroy activity {com.faegroup.app/com.faegroup.app.MainActivity}: kotlin.UninitializedPropertyAccessException: lateinit property token has not been initialized
    at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:5654)
    at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:5687)
    at android.app.servertransaction.DestroyActivityItem.execute(DestroyActivityItem.java:47)
    at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2374)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:233)
    at android.os.Looper.loop(Looper.java:344)
    at android.app.ActivityThread.main(ActivityThread.java:8249)
    at java.lang.reflect.Method.invoke(Method.java)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:589)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1071)
kotlin.UninitializedPropertyAccessException: lateinit property token has not been initialized
    at com.amazonaws.amplify.amplify_datastore.DataStoreHubEventStreamHandler.onCancel(DataStoreHubEventStreamHandler.kt:226)
    at com.amazonaws.amplify.amplify_datastore.AmplifyDataStorePlugin.onDetachedFromEngine(AmplifyDataStorePlugin.kt:195)
    at io.flutter.embedding.engine.FlutterEngineConnectionRegistry.remove(FlutterEngineConnectionRegistry.java:272)
    at io.flutter.embedding.engine.FlutterEngineConnectionRegistry.remove(FlutterEngineConnectionRegistry.java:280)
    at io.flutter.embedding.engine.FlutterEngineConnectionRegistry.removeAll(FlutterEngineConnectionRegistry.java:288)
    at io.flutter.embedding.engine.FlutterEngineConnectionRegistry.destroy(FlutterEngineConnectionRegistry.java:123)
    at io.flutter.embedding.engine.FlutterEngine.destroy(FlutterEngine.java:473)
    at io.flutter.embedding.android.FlutterActivityAndFragmentDelegate.onDetach(FlutterActivityAndFragmentDelegate.java:772)
    at io.flutter.embedding.android.FlutterActivity.onDestroy(FlutterActivity.java:909)
    at android.app.Activity.performDestroy(Activity.java:8406)
    at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1378)
    at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:5641)
    at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:5687)
    at android.app.servertransaction.DestroyActivityItem.execute(DestroyActivityItem.java:47)
    at android.app.servertransaction.ActivityTransactionItem.execute(ActivityTransactionItem.java:45)
    at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2374)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loopOnce(Looper.java:233)
    at android.os.Looper.loop(Looper.java:344)
    at android.app.ActivityThread.main(ActivityThread.java:8249)
    at java.lang.reflect.Method.invoke(Method.java)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:589)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1071)

Categories

  • [ ] Analytics
  • [ ] API (REST)
  • [ ] API (GraphQL)
  • [ ] Auth
  • [ ] Authenticator
  • [x] DataStore
  • [ ] Notifications (Push)
  • [ ] Storage

Steps to Reproduce

  1. Add the amplify_datastore package to a Flutter project (via pubspec.yaml).
  2. Do not call Amplify.addPlugin() with AmplifyDataStore, and do not interact with Amplify in any way.
  3. Run the app on an Android device.

Screenshots

No response

Platforms

  • [ ] iOS
  • [x] Android
  • [ ] Web
  • [ ] macOS
  • [ ] Windows
  • [ ] Linux

Flutter Version

3.29.2

Amplify Flutter Version

2.6.1

Deployment Method

Amplify CLI (Gen 1)

Schema


giulitu95 avatar Apr 08 '25 10:04 giulitu95

Hi @giulitu95, this is very strange, I'm sorry you are facing this. I'll try to reproduce this and get back to you

ekjotmultani avatar Apr 09 '25 16:04 ekjotmultani

Hello @giulitu95, I agree that just adding the DataStore package should not cause any exceptions or crashes so we will mark this as a bug. In the meantime you seem to have a work around of not including DataStore in your pubspec.yaml while you are not using it.

however I've been unable to reproduce the issue on my end despite verifying amplify_datastore is present in my pubspec.lock file and not referencing Amplify with my code. Do you have any addition reproduction steps or a minimal reproducible example?

  amplify_datastore:
    dependency: "direct main"
    description:
      name: amplify_datastore
      sha256: "8c9555e0ae12e3d1bf55cb7b248fb2dbfd3594fa19ac60a1ae88554b06709b95"
      url: "https://pub.dev"
    source: hosted
    version: "2.6.1"

tyllark avatar Apr 18 '25 00:04 tyllark

Hello @giulitu95, are you still experiencing this issue, if so could you please provide a minimal reproducible example.

tyllark avatar Apr 28 '25 19:04 tyllark

Hello @tyllark, currently I cannot provide a minimal reproducible example. Many android users of my application reported this problem through the error tracking system I'm using (sentry). During the development phase and test of my app I never encountered this issue

giulitu95 avatar Apr 30 '25 14:04 giulitu95

Hi @giulitu95, thanks for the additional information. It will be hard to verify a fix since we are unable to reproduce the issue, but we will work with the Amplify Android team to try and create a minimal reproducible example.

tyllark avatar Apr 30 '25 17:04 tyllark

Hi @tyllark We are also facing the same crash -

      Fatal Exception: androidx.datastore.preferences.protobuf.r0: lateinit property token has not been initialized
   at com.amazonaws.amplify.amplify_datastore.DataStoreHubEventStreamHandler.onCancel(DataStoreHubEventStreamHandler.kt:226)
   at com.amazonaws.amplify.amplify_datastore.AmplifyDataStorePlugin.onDetachedFromEngine(AmplifyDataStorePlugin.kt:195)
   at io.flutter.embedding.engine.FlutterEngineConnectionRegistry.remove(FlutterEngineConnectionRegistry.java:272)
   at io.flutter.embedding.engine.FlutterEngineConnectionRegistry.remove(FlutterEngineConnectionRegistry.java:280)
   at io.flutter.embedding.engine.FlutterEngineConnectionRegistry.removeAll(FlutterEngineConnectionRegistry.java:288)
   at io.flutter.embedding.engine.FlutterEngineConnectionRegistry.destroy(FlutterEngineConnectionRegistry.java:123)
   at io.flutter.embedding.engine.FlutterEngine.destroy(FlutterEngine.java:470)
   at dev.fluttercommunity.workmanager.BackgroundWorker.stopEngine$lambda$3(BackgroundWorker.java:143)
   at android.os.Handler.handleCallback(Handler.java:938)
   at android.os.Handler.dispatchMessage(Handler.java:99)
   at android.os.Looper.loopOnce(Looper.java:201)
   at android.os.Looper.loop(Looper.java:288)
   at android.app.ActivityThread.main(ActivityThread.java:7842)
   at java.lang.reflect.Method.invoke(Method.java)
   at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)

amruth-movano avatar Jun 02 '25 12:06 amruth-movano

im also facing same issue

omarfarukfindit avatar Jun 03 '25 13:06 omarfarukfindit

Hi @tyllark @ekjotmultani is there any update on this?

amruth-movano avatar Jun 05 '25 04:06 amruth-movano

@amruth-movano @omarfarukfindit, sorry you are also facing this problem, we will investigate further on this. Would you folks be willing to share your pubspec.yaml and the entry point to your applications as well so that we can try and reproduce this issue?

ekjotmultani avatar Jun 05 '25 20:06 ekjotmultani

pubspec.txt

We are initializing it like below -

// Runner.Dart

Future _runApp(Environment env) async { await runZonedGuarded( () async { WidgetsFlutterBinding.ensureInitialized(); try { await FlutterDisplayMode.setHighRefreshRate(); } catch (e) { print(e.toString()); }

  await configureAppPlugins(env); // Amplify call

  await SystemChrome.setPreferredOrientations([
    DeviceOrientation.portraitUp,
  ]);

  runApp(const MyApp());
  scheduleBgService();
},
reportCrash,

); }

Future configureAppPlugins(Environment env) async { currentEnv = env; await setUpServiceLocator(); await AndroidAlarmManager.initialize();

await Workmanager().initialize( callbackDispatcher, isInDebugMode: false );

try { await configureAmplify(env); // amplify configuration } on AmplifyAlreadyConfiguredException { debugPrint('Amplify configuration failed.'); }

FlutterError.onError = (FlutterErrorDetails details) { if (details.stack != null) { Zone.current.handleUncaughtError(details.exception, details.stack!); } }; }

Future configureAmplify(Environment env) async { //read json String amplifyConfig = await loadAsset(getEnvName(env.buildType));

final api = AmplifyAPI( options: APIPluginOptions(modelProvider: CustomModelProvider()), ); await Amplify.addPlugin(AmplifyAuthCognito()); await Amplify.addPlugin(api); final s3Plugin = AmplifyStorageS3(); await Amplify.addPlugin(s3Plugin); await DatastoreManager.initialize(); try { await Amplify.configure(amplifyConfig); } catch (ex) { debugPrint("Exception in amplify configure $ex"); Logger.log( tag: LogTag.***, message: "crash : Exception in amplify configure $ex"); } }

Future<String> loadAsset(String env) async { try { String value = await rootBundle.loadString('.env/$env/amplifyconfiguration.json'); return value; } on Exception catch (e) { Logger.log(tag: LogTag.***, message: "crash : loadAsset failed $e"); } return ""; }

amruth-movano avatar Jun 06 '25 06:06 amruth-movano

Thank you for sharing

ekjotmultani avatar Jun 09 '25 04:06 ekjotmultani

@ekjotmultani any update on this?

amruth-movano avatar Jun 23 '25 15:06 amruth-movano

Hello @amruth-movano sorry for the delayed reply. WorkManager is destroying the Flutter engine which triggers the native Android dispose/cleanup logic which leaves us with uninitialized properties, you can see a similar error here.

Amplify Flutter does not support isolates or WorkManager at this time, but we have a feature request open to gauge interest.

tyllark avatar Jun 23 '25 22:06 tyllark