# Error Handling

This guide outlines the error handling architecture and best practices used in AWS Logs MCP.

## Core Principles

1. **Error Classification**: Errors are classified as either operational (expected, runtime errors) or programming (bugs, unexpected errors).
2. **Error Context**: All errors include relevant context to assist in debugging without exposing sensitive information.
3. **Consistent API**: Error responses follow a consistent structure for clients.
4. **Security**: Error messages never expose sensitive information.

## Error Types

### BaseError

The foundation for all application errors with the following properties:

- `message`: Human-readable error description
- `statusCode`: HTTP status code (for API responses)
- `isOperational`: Indicates if error is expected (operational) or unexpected (programming)
- `errorCode`: Machine-readable error code
- `originalError`: Original error that was caught (for logging)

### AWS Service Errors

`AwsServiceError` extends BaseError with additional AWS-specific properties:

- `serviceName`: The AWS service that generated the error
- `operation`: The operation being performed
- `awsRequestId`: AWS request ID for tracing
- `awsErrorType`: AWS error type/code
- `awsStatusCode`: AWS HTTP status code

Example:
```typescript
throw new AwsServiceError(
  'Failed to retrieve log groups',
  'CloudWatchLogs',
  'listLogGroups',
  originalError
);
```

### Tool Execution Errors

`ToolExecutionError` extends BaseError for MCP tool-related errors:

- `toolName`: Name of the MCP tool
- `toolParams`: Parameters provided to the tool (sanitized)

Example:
```typescript
throw new ToolExecutionError(
  'Failed to retrieve logs',
  'cloudWatchLogs',
  { logGroupName, limit },
  originalError
);
```

### Other Error Types

- `ConfigurationError`: For errors related to application configuration
- `ValidationError`: For invalid input validation
- `TransportError`: For communication/transport issues

## Error Handling Middleware

Express middleware handles errors by:

1. Determining if the error is operational or programming
2. Logging appropriately (info level for operational, error level for programming)
3. Formatting the error response for the client
4. Setting the appropriate HTTP status code

## Error Response Format

Clients receive a consistent error response:

```json
{
  "error": "ERROR_CODE",
  "message": "Human-readable error message",
  "timestamp": "2023-01-01T00:00:00.000Z",
  
  // Optional context fields depending on error type
  "service": "CloudWatchLogs",     // For AWS errors
  "operation": "listLogGroups",    // For AWS errors
  "requestId": "abc123",           // For AWS errors
  "tool": "cloudWatchLogs",        // For tool errors
  "validationErrors": [...]        // For validation errors
}
```

## AWS Error Handling

AWS errors are mapped to appropriate HTTP status codes:
- 400: InvalidParameterException, ValidationException, etc.
- 401: UnauthorizedException, UnrecognizedClientException
- 403: AccessDeniedException
- 404: ResourceNotFoundException
- 503: ThrottlingException, ServiceUnavailableException

## Best Practices

1. **Always catch and properly wrap errors**: Use `wrapAwsError` for AWS SDK errors.
2. **Include operation context**: Always specify what operation was being performed.
3. **Never expose credentials**: Sanitize error objects before logging.
4. **Use structured logging**: Include request IDs and other correlation identifiers.
5. **Distinguish between operational and programming errors**: Log and handle accordingly.
6. **Use consistent error responses**: Follow the established response format.
7. **Include appropriate status codes**: Map error types to appropriate HTTP status codes.

## Examples

### Service Layer

```typescript
try {
  const command = new DescribeLogGroupsCommand(params);
  const response = await this.client.send(command);
  return response.logGroups || [];
} catch (error) {
  logger.error('Error listing log groups:', error);
  throw wrapAwsError(error, 'CloudWatchLogs', 'listLogGroups');
}
```

### Tool Layer

```typescript
try {
  const logGroups = await service.listLogGroups({ prefix, limit });
  return { content: [{ type: 'text', text: formatLogGroups(logGroups) }] };
} catch (error) {
  logger.error('Error in cloudWatchLogGroups tool:', error);
  throw new ToolExecutionError(
    `Failed to list log groups: ${error.message}`,
    'cloudWatchLogGroups',
    { prefix, limit },
    error
  );
}
```