immich-app/immich · error · Exception
User must be logged in to access recently taken
Error message
User must be logged in to access recently taken
What it means
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.
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).
Example fix
// before
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception('User must be logged in to access recently taken');
}
// after
final user = ref.watch(currentUserProvider);
if (user == null) {
return const SizedBox.shrink(); // or render a 'please log in' widget
} Defensive patterns
Strategy: try-catch
Validate before calling
final user = ref.watch(currentUserProvider);
if (user == null || !authService.isSessionValid) {
// route to login before accessing the page
return;
} Type guard
bool isAuthenticated(User? u) => u != null && u.id.isNotEmpty;
Try / catch
try {
final timeline = ref.watch(timelineServiceProvider);
// render page
} catch (e) {
if (e.toString().contains('User must be logged in')) {
context.go('/login');
} else {
rethrow;
}
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- User must be logged in to access trash
- User must be logged in to video
- User must be logged in to access archive
- User must be logged in to access archive
- User must be logged in to access favorite
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/86cbf4611470f546.
Report an issue: GitHub.
Appendix: source
Thrown at mobile/lib/presentation/pages/recently_taken.page.dart:21
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/widgets/timeline/timeline.widget.dart';
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/widgets/common/mesmerizing_sliver_app_bar.dart';
@RoutePage()
class RecentlyTakenPage extends StatelessWidget {
const RecentlyTakenPage({super.key});
@override
Widget build(BuildContext context) {
return ProviderScope(
overrides: [
timelineServiceProvider.overrideWith((ref) {
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception('User must be logged in to access recently taken');
}
final timelineService = ref.watch(timelineFactoryProvider).remoteAssets(user.id);
ref.onDispose(timelineService.dispose);
return timelineService;
}),
],
child: Timeline(appBar: MesmerizingSliverAppBar(title: context.t.recently_taken)),
);
}
}
View on GitHub (pinned to e55ac299a4)