immich-app/immich · error · Exception

User must be logged in to access trash

Error message

User must be logged in to access trash

What it means

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.

Solutions

  1. Guard navigation so the Trash page is only reachable when a user is logged in.
  2. Wait for the auth state (AsyncValue) to resolve before building the provider override.
  3. Restore or refresh the session, then re-authenticate the user.
  4. Render a login/unauthenticated placeholder 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 trash');
}
// 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);
  // render trash page
} catch (e) {
  if (e.toString().contains('User must be logged in')) {
    context.go('/login');
  } else {
    rethrow;
  }
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of immich-app/immich@e55ac299a4 (2026-09-15). Data as JSON: /api/errors/91ad817596d70d69. Report an issue: GitHub.

Appendix: source

Thrown at mobile/lib/presentation/pages/trash.page.dart:27

import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
import 'package:immich_mobile/providers/server_info.provider.dart';
import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/widgets/common/confirm_dialog.dart';
import 'package:immich_mobile/widgets/common/immich_toast.dart';

@RoutePage()
class TrashPage extends StatelessWidget {
  const TrashPage({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 trash');
          }

          final timelineService = ref.watch(timelineFactoryProvider).trash(user.id);
          ref.onDispose(timelineService.dispose);
          return timelineService;
        }),
      ],
      child: Timeline(
        appBar: SliverAppBar(
          title: Text(context.t.trash),
          floating: true,
          snap: true,
          pinned: true,
          centerTitle: true,
          elevation: 0,
          actions: const [_TrashKebabMenu()],
        ),
        topSliverWidgetHeight: 24,

View on GitHub (pinned to e55ac299a4)