{"record":{"id":"91ad817596d70d69","repo":"immich-app/immich","slug":"user-must-be-logged-in-to-access-trash","errorCode":null,"errorMessage":"User must be logged in to access trash","messagePattern":"User must be logged in to access trash","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"mobile/lib/presentation/pages/trash.page.dart","lineNumber":27,"sourceCode":"import 'package:immich_mobile/providers/infrastructure/action.provider.dart';\nimport 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';\nimport 'package:immich_mobile/providers/server_info.provider.dart';\nimport 'package:immich_mobile/providers/user.provider.dart';\nimport 'package:immich_mobile/widgets/common/confirm_dialog.dart';\nimport 'package:immich_mobile/widgets/common/immich_toast.dart';\n\n@RoutePage()\nclass TrashPage extends StatelessWidget {\n  const TrashPage({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 trash');\n          }\n\n          final timelineService = ref.watch(timelineFactoryProvider).trash(user.id);\n          ref.onDispose(timelineService.dispose);\n          return timelineService;\n        }),\n      ],\n      child: Timeline(\n        appBar: SliverAppBar(\n          title: Text(context.t.trash),\n          floating: true,\n          snap: true,\n          pinned: true,\n          centerTitle: true,\n          elevation: 0,\n          actions: const [_TrashKebabMenu()],\n        ),\n        topSliverWidgetHeight: 24,","sourceCodeStart":9,"sourceCodeEnd":45,"githubUrl":"https://github.com/immich-app/immich/blob/e55ac299a4ec7cb372e35dbf2c6c05ee9ce77f6c/mobile/lib/presentation/pages/trash.page.dart#L9-L45","documentation":"Thrown by the timelineServiceProvider override in the Trash page when currentUserProvider is null. The Trash timeline requires a user id to call timelineFactoryProvider.trash(user.id); without an authenticated user the service cannot be built. It indicates the Trash screen was opened in an unauthenticated state.","triggerScenarios":"Opening the Trash page before login, after session expiry/logout, or during app startup while auth state is still being restored and the provider reads null.","commonSituations":"Stale auth token expired server-side; a deep link to trash opened pre-login; navigating back to the tab after the user logged out on another device.","solutions":["Guard navigation so the Trash page is only reachable when a user is logged in.","Wait for the auth state (AsyncValue) to resolve before building the provider override.","Restore or refresh the session, then re-authenticate the user.","Render a login/unauthenticated placeholder instead of throwing when user is null."],"exampleFix":"// before\nfinal user = ref.watch(currentUserProvider);\nif (user == null) {\n  throw Exception('User must be logged in to access trash');\n}\n// after\nfinal user = ref.watch(currentUserProvider);\nif (user == null) {\n  return const SizedBox.shrink(); // or redirect to login\n}","handlingStrategy":"try-catch","validationCode":"final user = ref.watch(currentUserProvider);\nif (user == null) {\n  context.go('/login');\n  return;\n}","typeGuard":"bool isAuthenticated(User? u) => u != null && u.id.isNotEmpty;","tryCatchPattern":"try {\n  final timeline = ref.watch(timelineServiceProvider);\n  // render trash 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":["Only navigate to Trash from authenticated UI","Await auth state before watching user-scoped providers","Handle token expiry with silent refresh","Render an unauthenticated placeholder rather than throwing"],"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"}