{"record":{"id":"86cbf4611470f546","repo":"immich-app/immich","slug":"user-must-be-logged-in-to-access-recently-taken-page","errorCode":null,"errorMessage":"User must be logged in to access recently taken","messagePattern":"User must be logged in to access recently taken","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"mobile/lib/presentation/pages/recently_taken.page.dart","lineNumber":21,"sourceCode":"import 'package:hooks_riverpod/hooks_riverpod.dart';\nimport 'package:immich_mobile/generated/translations.g.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 RecentlyTakenPage extends StatelessWidget {\n  const RecentlyTakenPage({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 recently taken');\n          }\n\n          final timelineService = ref.watch(timelineFactoryProvider).remoteAssets(user.id);\n          ref.onDispose(timelineService.dispose);\n          return timelineService;\n        }),\n      ],\n      child: Timeline(appBar: MesmerizingSliverAppBar(title: context.t.recently_taken)),\n    );\n  }\n}\n","sourceCodeStart":3,"sourceCodeEnd":33,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/mobile/lib/presentation/pages/recently_taken.page.dart#L3-L33","documentation":"This error is thrown by the timelineServiceProvider override in the Recently Taken page's build method. When the Riverpod currentUserProvider resolves to null, the page cannot construct a TimelineService (which requires a user id), so it throws synchronously during provider initialization. It signals that the screen was rendered without an authenticated user.","triggerScenarios":"Navigating to the Recently Taken page while currentUserProvider yields null — e.g. before login completes, after session token expiry with a stale cached user, or during a race where auth state is still loading when the page builds.","commonSituations":"Deep-links or push notifications opening the page before login; the app restoring the tab after logout; auth API returning no user due to expired tokens or server logout.","solutions":["Ensure the user is authenticated before routing to this page (redirect unauthenticated sessions to the login screen).","Gate the page on an auth-ready AsyncValue so it waits for currentUserProvider to resolve instead of reading null.","On receiving this error, refresh/restore the session and re-login, then reload the page.","Handle the null case gracefully in the override (show a login prompt widget instead of throwing)."],"exampleFix":"// before\nfinal user = ref.watch(currentUserProvider);\nif (user == null) {\n  throw Exception('User must be logged in to access recently taken');\n}\n// after\nfinal user = ref.watch(currentUserProvider);\nif (user == null) {\n  return const SizedBox.shrink(); // or render a 'please log in' widget\n}","handlingStrategy":"try-catch","validationCode":"final user = ref.watch(currentUserProvider);\nif (user == null || !authService.isSessionValid) {\n  // route to login before accessing the page\n  return;\n}","typeGuard":"bool isAuthenticated(User? u) => u != null && u.id.isNotEmpty;","tryCatchPattern":"try {\n  final timeline = ref.watch(timelineServiceProvider);\n  // render page\n} catch (e) {\n  if (e.toString().contains('User must be logged in')) {\n    context.go('/login');\n  } else {\n    rethrow;\n  }\n}","preventionTips":["Guard authenticated routes with a redirect that checks currentUserProvider","Wait for auth AsyncValue to resolve before building user-dependent providers","Refresh session tokens before they expire","Show a login prompt widget instead of throwing in provider overrides"],"tags":["authentication","flutter","riverpod","state"],"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"}