Fix: Silent Production Errors (Batch)

Branch: fix/silent-errors-batch Date: 2026-03-18 Impact: 9 error categories that crashed silently without being reported to Supabase

Overview

A batch of production errors was identified that were not being caught or reported to the app_issues table in Supabase. These spanned several services and were grouped into 9 categories. All have been fixed and all catch blocks now properly report via IssueReportService.


Error 1 — Squad fetching (squad_service.dart)

Root cause: getMySquad() ordered by .order('joined_at') — this column does not exist in squad_members. PostgREST threw a PostgrestException which was swallowed silently.

Fix: Changed to .order('created_at', ascending: false).


Error 2 — PostgrestException in notifications (notification_repository.dart)

Root cause: getNotifications() had no try-catch at all. Any Supabase error propagated uncaught into the caller. Additionally, it fetched all notifications (missing user_id filter).

Fix:

  • Wrapped all three methods (getNotifications, markAsRead, markAllAsRead) in try-catch.
  • Added .eq('user_id', userId) filter to getNotifications().
  • All catch blocks now report to IssueReportService.

Error 3 — Exception from image resource service (storage_service.dart)

Root cause: uploadProfileImage() accepted a dart:io File, which throws UnsupportedError on Flutter Web. The MIME type was also derived from file.path (a blob: URL on web), yielding a garbage extension.

Fix:

  • Changed parameter from File to XFile (from image_picker).
  • Uses file.name for extension extraction (real filename, not blob URL).
  • Uses file.readAsBytes() instead of File.readAsBytes() — cross-platform.
  • Switched from .upload() to .uploadBinary().
  • Normalizes jpgimage/jpeg MIME type.

Error 4 — UnimplementedError in image picker (registration_wizard_notifier.dart)

Root cause: pickImage() called ImageCropper().cropImage() and File(croppedFile.path) on Flutter Web — both unsupported, throwing UnimplementedError.

Fix:

  • Added kIsWeb guard: skips ImageCropper entirely on web.
  • On native, wrapped ImageCropper call in try-catch with fallback to original XFile.
  • Changed File(croppedFile.path)XFile(croppedFile.path) to match updated StorageService signature.

Error 5 — PostgrestException in social list (social_list_screen.dart)

Root cause: _fetchFollowers() and _fetchFollowing() used PostgREST FK hint syntax (profiles!friendships_user_id_fkey(...)). If the FK constraint name doesn’t exactly match the schema, PostgREST returns a PGRST200 error.

Fix: Replaced with explicit two-step queries — first fetch IDs from friendships, then fetch matching profiles with .inFilter('id', ids). More verbose but reliable.


Error 6 — PostgrestException: count cast (crew_service.dart)

Root cause: getActiveCrews() cast the PostgREST count result directly: members[0]['count'] as int. PostgREST may return count as a String depending on version/configuration, causing a type cast exception.

Fix: Changed to int.tryParse(members[0]['count'].toString()) ?? 0 — handles both String and int safely.


Error 7 — PostgrestException in squad search (search_screen.dart)

Root cause: The search query on the squads table used .ilike('title', ...) — but the squads table has no title column. The actual searchable column is vibe_tag.

Fix: Changed to .ilike('vibe_tag', '%$query%').


Error 8 — Always-silent errors in notification provider (notification_provider.dart)

Root cause: NotificationNotifier used print() for all error output — errors were logged to console only and never reported. Also missing user_id filter in loadNotifications() and markAllAsRead().

Fix:

  • Replaced all print() calls with IssueReportService().reportIssue(...).
  • Added user_id filter to loadNotifications() and markAllAsRead().
  • Added early return if user is not authenticated.

Error 9 — PostgrestException in crew fetching (crew_service.dart)

Root cause: getMyCrew() ordered crew_members by .order('joined_at') — same as Error 1 pattern. joined_at does not exist; the correct column is created_at.

Fix: Changed to .order('created_at', ascending: false).


Files Changed

FileChanges
lib/features/social/services/squad_service.dartjoined_atcreated_at, added IssueReportService
lib/shared/repositories/notification_repository.darttry-catch for all methods, user_id filter
lib/core/services/storage_service.dartFileXFile, readAsBytes(), extension from file.name
lib/features/auth/notifiers/registration_wizard_notifier.dartkIsWeb guard, XFile instead of File
lib/features/profile/screens/social_list_screen.dartFK hints removed, two-step explicit queries
lib/features/social/services/crew_service.dartSafe count cast, joined_atcreated_at, IssueReportService
lib/features/search/screens/search_screen.darttitlevibe_tag for squads search
lib/shared/providers/notification_provider.dartprint()IssueReportService, user_id filter