Error Handling & ResultFuture
Relevant source files
The following files were used as context for generating this wiki page:
Introduction
MoodTune implements a robust, type-safe error handling strategy centered around the functional programming pattern of "Either". Instead of relying on traditional try-catch blocks throughout the presentation layer, the architecture utilizes a ResultFuture<T> type. This approach forces developers to explicitly handle both success and failure cases at compile time, ensuring that errors in network requests, authentication, or audio analysis are managed gracefully and communicated clearly to the user.
This system is integrated within a Clean Architecture framework, where data sources throw exceptions, repositories catch those exceptions and map them to failures, and the presentation layer consumes these failures through BLoC state changes. This ensures a clear separation of concerns and a consistent user experience across the app's various features, including Authentication and Routing.
Sources: CLAUDE.md:38-42, authplan.md:144-150
The ResultFuture Pattern
The core of the project's error handling is the ResultFuture<T> typedef. It leverages the dartz library's Either type to return either a Failure (on the left) or the expected data T (on the right).
// lib/utils/typedef.dart
typedef ResultFuture<T> = Future<Either<Failure, T>>;
This pattern is applied to all repository contracts and use cases to maintain consistency.
Data Flow for Errors
The following diagram illustrates how an error originates in a remote data source and propagates through the system until it is handled by the UI.
Sources: CLAUDE.md:65-72, authplan.md:140-155, pubspec.yaml:16
Failure and Exception Hierarchies
The system distinguishes between Exceptions (internal technical issues in the Data Layer) and Failures (business-logic errors passed to the Domain and Presentation layers).
Exception Types
Data sources throw typed exceptions from lib/core/error/exceptions.dart. These often originate from network issues or API-specific failures.
| Exception Class | Origin | Description |
|---|---|---|
ServerException | Remote Data Sources | Issues communicating with FastAPI or Jamendo APIs |
CacheException | Local Data Sources | Failures in local storage or session persistence |
AuthException | Supabase Service | Errors during login, signup, or token refresh |
Sources: CLAUDE.md:74-76, authplan.md:152-155
Failure Types
Repositories map exceptions to Failures defined in lib/core/error/failures.dart.
| Failure Class | Description |
|---|---|
AuthFailure | Authentication errors (invalid credentials, user exists) |
NetworkFailure | Connection issues or timeouts |
ServerFailure | Backend API errors (500 series) |
AnalysisFailure | Errors specific to song/audio analysis processing |
Sources: CLAUDE.md:74-76, authplan.md:152-160
Implementation in Repositories
Repositories serve as the "translation layer" for errors. They perform network connectivity checks and wrap data source calls in try-catch blocks to convert exceptions into Left(Failure).
Sources: authplan.md:152-165, CLAUDE.md:55-60
Presentation Layer Integration
BLoCs consume ResultFuture using the fold method, which provides two callbacks: one for the failure case and one for the success case.
Consumption Example
final result = await _repository.login(email, password);
result.fold(
(failure) => emit(state.copyWith(
status: AuthStatus.error,
error: failure.message
)),
(user) => emit(state.copyWith(
status: AuthStatus.authenticated,
user: user
)),
);
Global Error Handling in UI
The AppRouter provides a global errorBuilder to handle routing-specific failures, such as navigation to non-existent pages (404).
Sources: CLAUDE.md:67-72, routing_plan.md:350-365, authplan.md:200-210
Network-Specific Handling
The application uses Dio with specialized interceptors to handle common network-level errors:
- AuthInterceptor: Intercepts 401 Unauthorized responses to attempt a Supabase session refresh. If refresh fails, it retries the request or propagates the error.
- RetryInterceptor: Automatically retries failed requests under specific conditions.
- SentryDio: Captures and reports exceptions to Sentry for monitoring.
- TalkerDioLogger: Provides structured logging for debugging network failures in development.
Sources: CLAUDE.md:92-100, authplan.md:75-90, pubspec.yaml:28-29
Summary
Error handling in MoodTune is a proactive rather than reactive process. By utilizing ResultFuture, the architecture ensures that developers cannot ignore error states. The conversion of Exceptions to Failures allows the application to provide user-friendly messages while maintaining technical details in logs through Talker and Sentry. This tiered approach—from interceptors at the network level to fold logic in the BLoC—creates a resilient application capable of handling complex audio analysis and authentication workflows.
Sources: CLAUDE.md:40-42, README.md:15, authplan.md:245-255