home / skills / kaakati / rails-enterprise-dev / error-handling
This skill explains error handling patterns using exception, failure, and Either types to create robust, scalable error flows.
npx playbooks add skill kaakati/rails-enterprise-dev --skill error-handlingReview the files below or copy the command above to add this skill to your agents.
---
name: "Error Handling Patterns"
description: "Exception classes, failure classes, Either type, and error handling strategies"
version: "1.0.0"
---
# Error Handling Patterns
## Exception Classes (Data Layer)
```dart
abstract class AppException implements Exception {
final String message;
final String? code;
const AppException({required this.message, this.code});
}
class ServerException extends AppException {
final int? statusCode;
const ServerException({
required super.message,
super.code,
this.statusCode,
});
}
class CacheException extends AppException {
const CacheException({required super.message, super.code});
}
class NetworkException extends AppException {
const NetworkException({
super.message = 'No internet connection',
super.code,
});
}
```
## Failure Classes (Domain Layer)
```dart
import 'package:equatable/equatable.dart';
abstract class Failure extends Equatable {
final String message;
const Failure(this.message);
@override
List<Object> get props => [message];
}
class ServerFailure extends Failure {
const ServerFailure(super.message);
}
class CacheFailure extends Failure {
const CacheFailure(super.message);
}
class NetworkFailure extends Failure {
const NetworkFailure([super.message = 'No internet connection']);
}
```
## Either Type Usage
```dart
import 'package:dartz/dartz.dart';
// Repository returns Either<Failure, Entity>
Future<Either<Failure, User>> getUser(String id) async {
try {
final model = await provider.fetchUser(id);
return Right(model.toEntity());
} on ServerException catch (e) {
return Left(ServerFailure(e.message));
} on NetworkException {
return Left(NetworkFailure());
}
}
// Controller handles Either result
final result = await getUserUseCase('123');
result.fold(
(failure) => _handleError(failure),
(user) => _user.value = user,
);
```
This skill catalogs robust error handling patterns for enterprise Rails workflows adapted from layered application design. It describes exception classes at the data layer, failure classes at the domain layer, and how to use an Either-style result type to propagate and handle errors predictably. The goal is to make error flows explicit, testable, and portable across services and agents.
Define concrete exception types where errors originate (e.g., ServerException, CacheException, NetworkException) so low-level code can throw meaningful errors. Map those exceptions to domain-level Failure objects (e.g., ServerFailure, CacheFailure, NetworkFailure) inside repositories. Return results as Either<Failure, Entity> so callers explicitly handle success and failure paths without throwing. Controllers or use cases fold the Either to handle failures centrally and update application state on success.
Why convert exceptions to Failure objects?
To decouple low-level error details from business logic, make errors explicit in return types, and allow functional composition without throwing.
When should I still throw exceptions?
Reserve throws for unrecoverable conditions or programming errors. Use Failures for expected operational errors you want callers to handle.