{"record":{"id":"5b630a53cab96d94","repo":"immich-app/immich","slug":"user-must-be-logged-in-to-access-favorite","errorCode":null,"errorMessage":"User must be logged in to access favorite","messagePattern":"User must be logged in to access favorite","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"mobile/lib/presentation/pages/favorite.page.dart","lineNumber":22,"sourceCode":"import 'package:immich_mobile/generated/translations.g.dart';\nimport 'package:immich_mobile/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.dart';\nimport 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart';\nimport 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';\nimport 'package:immich_mobile/providers/user.provider.dart';\nimport 'package:immich_mobile/widgets/common/mesmerizing_sliver_app_bar.dart';\n\n@RoutePage()\nclass FavoritePage extends StatelessWidget {\n  const FavoritePage({super.key});\n\n  @override\n  Widget build(BuildContext context) {\n    return ProviderScope(\n      overrides: [\n        timelineServiceProvider.overrideWith((ref) {\n          final user = ref.watch(currentUserProvider);\n          if (user == null) {\n            throw Exception('User must be logged in to access favorite');\n          }\n\n          final timelineService = ref.watch(timelineFactoryProvider).favorite(user.id);\n          ref.onDispose(timelineService.dispose);\n          return timelineService;\n        }),\n      ],\n      child: Timeline(\n        appBar: MesmerizingSliverAppBar(title: context.t.favorites, icon: Icons.favorite_outline),\n        bottomSheet: const FavoriteBottomSheet(),\n      ),\n    );\n  }\n}\n","sourceCodeStart":4,"sourceCodeEnd":37,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/mobile/lib/presentation/pages/favorite.page.dart#L4-L37","documentation":"This exception is thrown by the favorite page's timelineServiceProvider override when currentUserProvider evaluates to null. The favorite timeline service is constructed via timelineFactoryProvider.favorite(user.id), which is impossible without a logged-in user, so the provider throws deliberately instead of building a broken service. It signals that the page was reached without an authenticated session.","triggerScenarios":"Reading timelineServiceProvider on the favorite page while currentUserProvider is null — e.g. the auth stream has not emitted yet, the user logged out, or the page is opened before login completes.","commonSituations":"Deep link or push notification opening the favorites tab before auth bootstrap finishes; session expiry clearing the user while the favorites page stays mounted; auth provider misconfiguration so currentUser never becomes non-null.","solutions":["Gate navigation to the favorite page behind a non-null currentUser (auth redirect/guard).","Ensure session restoration runs on app start before any tab/route can be built.","Check that currentUserProvider is properly overridden/initialized in the root ProviderScope for this route.","On logout, navigate away from auth-required pages instead of leaving them in the tree."],"exampleFix":"// before\ntimelineServiceProvider.overrideWith((ref) {\n  final user = ref.watch(currentUserProvider);\n  if (user == null) {\n    throw Exception('User must be logged in to access favorite');\n  }\n  ...\n// after\ntimelineServiceProvider.overrideWith((ref) {\n  final user = ref.watch(currentUserProvider);\n  if (user == null) {\n    return Future.value(null); // let the page render a login prompt instead of throwing\n  }\n  ...","handlingStrategy":"validation","validationCode":"final user = ref.read(currentUserProvider);\nif (user == null) {\n  context.go('/login');\n  return;\n}","typeGuard":"bool isSignedIn(User? user) => user != null && user.id.isNotEmpty;","tryCatchPattern":"try {\n  final service = ref.read(timelineServiceProvider);\n} catch (e) {\n  if (e.toString().contains('User must be logged in')) {\n    context.go('/login');\n  } else {\n    rethrow;\n  }\n}","preventionTips":["Gate favorites navigation on non-null currentUser.","Log out via a central handler that also navigates away from auth-required pages.","Keep session persistence enabled so restarts resume a valid user.","Check auth provider initialization in tests and dev flavors.","Verify auth stream errors are surfaced rather than silently leaving the user null."],"tags":["flutter","riverpod","authentication","null-user"],"backgroundTag":"authentication-required","analyzedSha":"e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c","analyzedAt":"2026-09-15T07:20:19.675Z","contentChangedAt":"2026-09-15T07:20:19.675Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}