UninitializedPropertyAccessException crash on Android when amplify_datastore is included but not used
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
- Add the
amplify_datastorepackage to a Flutter project (viapubspec.yaml). - Do not call
Amplify.addPlugin()withAmplifyDataStore, and do not interact with Amplify in any way. - 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
Hi @giulitu95, this is very strange, I'm sorry you are facing this. I'll try to reproduce this and get back to you
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"
Hello @giulitu95, are you still experiencing this issue, if so could you please provide a minimal reproducible example.
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
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.
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)
im also facing same issue
Hi @tyllark @ekjotmultani is there any update on this?
@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?
We are initializing it like below -
// Runner.Dart
Future
await configureAppPlugins(env); // Amplify call
await SystemChrome.setPreferredOrientations([
DeviceOrientation.portraitUp,
]);
runApp(const MyApp());
scheduleBgService();
},
reportCrash,
); }
Future
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
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 ""; }
Thank you for sharing
@ekjotmultani any update on this?
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.