LogoFletch
Discord
fletchkartikey321/fletch 999999

Error Handling#

Fletch provides a robust error handling system that simplifies returning standard HTTP error responses and supports custom global error handling.

The HttpError Class#

The core of Fletch's error handling is the HttpError class. When you throw an HttpError (or a subclass) from any route or middleware, Fletch automatically catches it and sends a structured JSON response with the appropriate status code.

Built-in Error Types#

Fletch includes several pre-defined error classes for common scenarios:

  • HttpError(statusCode, message, [data]): Generic error.
  • ValidationError(message, [data]): 400 Bad Request.
  • UnauthorizedError(message, [data]): 401 Unauthorized.
  • NotFoundError(message, [data]): 404 Not Found.
  • RouteConflictError(message, [data]): 409 Conflict.

Usage Example#

Throwing errors in your routes allows execution to stop immediately and lets the framework handle the response.

app.get('/users/:id', (req, res) {
  final user = findUser(req.params['id']);
  
  if (user == null) {
    throw NotFoundError('User not found');
  }
  
  if (!user.isActive) {
    throw UnauthorizedError('Account disabled');
  }
  
  res.json(user);
});

The client will receive a 404 response body like:

{
  "error": "User not found",
  "data": null
}

Global Error Handler#

You can define a custom global error handler to control the exact format of your error responses or to integrate with logging services (like Sentry or Datadog).

Handler Signature#

typedef ErrorHandler = FutureOr<void> Function(
    dynamic error, Request request, Response response);

Configuration#

Pass your custom handler to app.setErrorHandler():

void main() {
  final app = Fletch();

  app.setErrorHandler((error, req, res) async {
    // 1. Log the error
    print('Error: $error');

    // 2. Handle known HttpErrors
    if (error is HttpError) {
      res.status(error.statusCode).json({
        'success': false,
        'error': {
          'code': error.statusCode,
          'message': error.message,
          'details': error.data,
        }
      });
      return;
    }

    // 3. Handle unexpected errors (hide details in production)
    res.status(500).json({
      'success': false,
      'error': {
        'code': 500,
        'message': 'Internal Server Error',
      }
    });
  });

  app.listen(3000);
}

Validation Errors#

The ValidationError class is perfect for returning detailed form validation issues.

app.post('/register', (req, res) async {
  final body = await req.body;
  
  if (body['email'] == null) {
    throw ValidationError('Invalid input', {'email': 'Email is required'});
  }
});

Response (400 Bad Request):

{
  "error": "Invalid input",
  "data": {
    "email": "Email is required"
  }
}