immich-app/immich · error · Exception
User must be logged in to access favorite
Error message
User must be logged in to access favorite
What it means
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.
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.
Example fix
// before
timelineServiceProvider.overrideWith((ref) {
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception('User must be logged in to access favorite');
}
...
// after
timelineServiceProvider.overrideWith((ref) {
final user = ref.watch(currentUserProvider);
if (user == null) {
return Future.value(null); // let the page render a login prompt instead of throwing
}
... Defensive patterns
Strategy: validation
Validate before calling
final user = ref.read(currentUserProvider);
if (user == null) {
context.go('/login');
return;
} Type guard
bool isSignedIn(User? user) => user != null && user.id.isNotEmpty;
Try / catch
try {
final service = ref.read(timelineServiceProvider);
} catch (e) {
if (e.toString().contains('User must be logged in')) {
context.go('/login');
} else {
rethrow;
}
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- User must be logged in to access archive
- User must be logged in to access locked folder
- User must be logged in to access recently taken
- User must be logged in to view person timeline
- User must be logged in to access archive
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/5b630a53cab96d94.
Report an issue: GitHub.
Appendix: source
Thrown at mobile/lib/presentation/pages/favorite.page.dart:22
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/presentation/widgets/bottom_sheet/favorite_bottom_sheet.widget.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 FavoritePage extends StatelessWidget {
const FavoritePage({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 favorite');
}
final timelineService = ref.watch(timelineFactoryProvider).favorite(user.id);
ref.onDispose(timelineService.dispose);
return timelineService;
}),
],
child: Timeline(
appBar: MesmerizingSliverAppBar(title: context.t.favorites, icon: Icons.favorite_outline),
bottomSheet: const FavoriteBottomSheet(),
),
);
}
}
View on GitHub (pinned to e55ac299a4)