{"record":{"id":"2b57be65e5dfa026","repo":"immich-app/immich","slug":"user-must-be-logged-in-to-access-recently-taken","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_added.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 RecentlyAddedPage extends StatelessWidget {\n  const RecentlyAddedPage({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).recentlyAdded(user.id);\n          ref.onDispose(timelineService.dispose);\n          return timelineService;\n        }),\n      ],\n      child: Timeline(appBar: MesmerizingSliverAppBar(title: context.t.recently_added)),\n    );\n  }\n}\n","sourceCodeStart":3,"sourceCodeEnd":33,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/mobile/lib/presentation/pages/recently_added.page.dart#L3-L33","documentation":"This exception is thrown by the recently-added page's timelineServiceProvider override when currentUserProvider yields null. The recently-taken timeline is user-scoped (timelineFactoryProvider.recentlyAdded(user.id)), so it cannot be built without a logged-in user; the provider throws this exception instead. It indicates the page was reached before authentication resolved.","triggerScenarios":"Opening the recently added page while currentUserProvider is null — first frame before auth initialization, logout clearing the user, or a route pushed without the login gate.","commonSituations":"App cold start landing on the recently-taken tab before session restore completes; auth token expiring silently so the user becomes null while the tab stays mounted; forgetting to initialize the auth provider in a test/dev build.","solutions":["Show a loading/login screen until currentUserProvider emits a user before rendering any timeline tab.","Persist and restore the session on startup so currentUser is available at first build.","Add a router redirect guarding all timeline pages behind authentication.","Confirm the auth provider is correctly initialized/overridden in the root ProviderScope."],"exampleFix":"// before\nfinal timelineService = ref.watch(timelineServiceProvider);\n// after\nfinal user = ref.watch(currentUserProvider);\nif (user == null) return const LoginPage();\nfinal timelineService = ref.watch(timelineServiceProvider);","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":["Render a login/loading screen until currentUser resolves before showing timeline tabs.","Restore the persisted session during app startup before first frame navigation.","Guard all timeline routes with a single shared auth redirect.","Ensure auth provider initialization is not skipped in any build flavor.","Write a cold-start signed-out test that opens the recently-added tab."],"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"}