Files
managing-apps/src/Managing.Core/Exceptions

Error Handling in Managing Application

This document describes the centralized error handling approach used in the Managing applications to ensure consistent error responses and logging, with Sentry integration for error monitoring.

Architecture

The error handling architecture consists of:

  1. Global Error Handling Middleware: Captures all unhandled exceptions and formats consistent responses
  2. Sentry Integration: Sends detailed error information to Sentry for monitoring and analysis
  3. Custom Exception Types: Provide appropriate HTTP status code mapping
  4. SentryErrorCapture Utility: Provides methods for manually capturing errors with context

Global Error Handling Middleware

The GlobalErrorHandlingMiddleware is registered in Program.cs for both the main API and Worker API:

app.UseMiddleware(typeof(GlobalErrorHandlingMiddleware));

When an exception occurs, the middleware:

  1. Determines the appropriate HTTP status code based on exception type
  2. Logs the error with request details
  3. Captures the exception in Sentry with appropriate context
  4. Returns a standardized JSON error response to the client

Sentry Integration

Sentry is integrated in three ways:

  1. Global Configuration: Set up in Program.cs with environment-specific settings
  2. Error Capture: In the global middleware and utility methods
  3. Diagnostic Endpoint: The SentryDiagnosticsMiddleware provides a test endpoint at /api/sentry-diagnostics

The captured data includes:

  • HTTP request details (path, method, query strings)
  • Exception details (type, message, stack trace)
  • Additional context from exception data
  • Tags for better categorization and filtering

Using Custom Exception Types

The shared exception types map to appropriate HTTP status codes:

Exception Type HTTP Status Code Use Case
ValidationException 400 Bad Request Input validation errors
NotFoundException 404 Not Found Resource does not exist
ForbiddenException 403 Forbidden Permission denied
ConflictException 409 Conflict Resource state conflict
RateLimitExceededException 429 Too Many Requests Rate limit exceeded
ServiceUnavailableException 503 Service Unavailable External service down

Example:

// Validation error
throw new ValidationException("The username must be at least 3 characters");

// Resource not found with context
throw new NotFoundException("User", userId);

// Permission denied
throw new ForbiddenException();

Manual Error Reporting

For manually reporting errors to Sentry, use the SentryErrorCapture utility:

// Capture an exception with context
SentryErrorCapture.CaptureException(ex, "MyService", new Dictionary<string, object> {
    { "userId", user.Id },
    { "operation", "ProcessImport" }
});

// Enrich an exception before throwing
throw SentryErrorCapture.EnrichException(new ValidationException("Invalid data"), 
    new Dictionary<string, object> {
        { "validationErrors", errors }
    });

Error Response Format

The standard error response format is:

{
  "statusCode": 400,
  "message": "The error message",
  "traceId": "sentry-event-id",
  "stackTrace": "Only included in non-production environments"
}

Best Practices

  1. Use custom exception types: Throw the appropriate exception type for each error case
  2. Add context to exceptions: Use the Data dictionary to add context that will be captured
  3. Don't duplicate Sentry reporting: Let the global middleware handle Sentry integration
  4. Avoid sensitive data: Never include sensitive data (passwords, tokens) in error messages or context
  5. Use the diagnostic endpoint: Test Sentry connectivity using the /api/sentry-diagnostics endpoint