immich-app/immich · error · Exception
User must be logged in to access archive
Error message
User must be logged in to access archive
What it means
Thrown by the timelineServiceProvider override in the map bottom sheet when currentUserProvider is null. Building the map timeline (users list, TimelineMapOptions stream) requires a user id, so an unauthenticated session makes the provider throw during build. It indicates the map sheet was opened without a logged-in user.
Solutions
- Only open the map sheet when a user is authenticated (check currentUserProvider first).
- Await the auth AsyncValue before building the sheet's provider overrides.
- Re-authenticate on this error and reopen the sheet.
- Render a login prompt / empty state instead of throwing when user is null.
Example fix
// before
final user = ref.watch(currentUserProvider);
if (user == null) {
throw Exception('User must be logged in to access archive');
}
// after
final user = ref.watch(currentUserProvider);
if (user == null) {
return const SizedBox.shrink(); // or redirect to login
} Defensive patterns
Strategy: try-catch
Validate before calling
final user = ref.watch(currentUserProvider);
if (user == null) {
context.go('/login');
return;
} Type guard
bool isAuthenticated(User? u) => u != null && u.id.isNotEmpty;
Try / catch
try {
final timeline = ref.watch(timelineServiceProvider);
// open map sheet
} catch (e) {
if (e.toString().contains('User must be logged in')) {
context.go('/login');
} else {
rethrow;
}
} Prevention
- Check currentUserProvider before opening the map bottom sheet
- Await auth restoration before user-scoped provider overrides
- Silently refresh expired sessions
- Render login prompt instead of throwing in build overrides
When it happens
Trigger: Opening the map bottom sheet while currentUserProvider is null — before login finishes, after logout/token expiry, or when auth state restoration hasn't completed when the sheet builds.
Common situations: Session expired in background then user taps the map button; deep link opening the map pre-login; stale credentials after a server-side logout.
Related errors
- User must be logged in to access map
- User must be logged in to access archive
- User must be logged in to access favorite
- User must be logged in to access locked folder
- User must be logged in to access recently taken
AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15).
Data as JSON: /api/errors/29916fc0e1526b2f.
Report an issue: GitHub.
Appendix: source
Thrown at mobile/lib/presentation/widgets/bottom_sheet/map_bottom_sheet.widget.dart:49
backgroundColor: context.themeData.colorScheme.surface,
slivers: const [
SliverFillRemaining(hasScrollBody: false, child: SizedBox(height: 0, child: _ScopedMapTimeline())),
],
);
}
}
class _ScopedMapTimeline extends StatelessWidget {
const _ScopedMapTimeline();
@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 archive');
}
final withPartners = ref.watch(mapStateProvider.select((s) => s.withPartners));
final users = withPartners ? ref.watch(timelineUsersProvider).valueOrNull ?? [user.id] : [user.id];
final optionsController = StreamController<TimelineMapOptions>.broadcast();
ref.onDispose(optionsController.close);
var currentOptions = ref.read(mapStateProvider).toOptions();
ref.listen(mapStateProvider.select((state) => state.toOptions()), (_, newOptions) {
currentOptions = newOptions;
optionsController.add(newOptions);
});
final timelineService = ref
.watch(timelineFactoryProvider)
.geographicMap(users, () => currentOptions, optionsController.stream);View on GitHub (pinned to e55ac299a4)