# Error System Documentation

This document describes the comprehensive error handling system implemented in readur for consistent, maintainable, and user-friendly error responses.

## Overview

The error system provides structured, typed error handling across all API endpoints with automatic integration into the existing error management and monitoring infrastructure.

## Architecture

### Core Components

1. **`src/errors/mod.rs`** - Central error module with shared traits and utilities
2. **Entity-specific error modules** - Dedicated error types for each domain:
   - `src/errors/user.rs` - User management errors
   - `src/errors/source.rs` - File source operation errors  
   - `src/errors/label.rs` - Label management errors
   - `src/errors/settings.rs` - Settings configuration errors
   - `src/errors/search.rs` - Search operation errors

### AppError Trait

All custom errors implement the `AppError` trait which provides:

```rust
pub trait AppError: std::error::Error + Send + Sync + 'static {
    fn status_code(&self) -> StatusCode;           // HTTP status code
    fn user_message(&self) -> String;              // User-friendly message
    fn error_code(&self) -> &'static str;          // Frontend error code
    fn error_category(&self) -> ErrorCategory;     // Error categorization
    fn error_severity(&self) -> ErrorSeverity;     // Severity level
    fn suppression_key(&self) -> Option<String>;   // For repeated error handling
    fn suggested_action(&self) -> Option<String>;  // Recovery suggestions
}
```

## Error Type Reference

The following table provides a comprehensive overview of all error types, when to use them, and their characteristics:

| Error Type | Module | When to Use | Common Scenarios | Example Error Codes | HTTP Status |
|------------|--------|-------------|------------------|-------------------|-------------|
| **ApiError** | `errors::mod` | Generic API errors when specific types don't apply | Rate limiting, payload validation, generic server errors | `BAD_REQUEST`, `NOT_FOUND`, `UNAUTHORIZED`, `INTERNAL_SERVER_ERROR` | 400, 401, 404, 500 |
| **UserError** | `errors::user` | User management and authentication operations | Registration, login, profile updates, permissions | `USER_NOT_FOUND`, `USER_DUPLICATE_USERNAME`, `USER_PERMISSION_DENIED` | 400, 401, 403, 404, 409 |
| **SourceError** | `errors::source` | File source operations (WebDAV, S3, Local Folder) | Source configuration, sync operations, connection issues | `SOURCE_CONNECTION_FAILED`, `SOURCE_AUTH_FAILED`, `SOURCE_SYNC_IN_PROGRESS` | 400, 401, 404, 409, 503 |
| **LabelError** | `errors::label` | Document labeling and label management | Creating/editing labels, label assignment, system labels | `LABEL_DUPLICATE_NAME`, `LABEL_IN_USE`, `LABEL_SYSTEM_MODIFICATION` | 400, 403, 404, 409 |
| **SettingsError** | `errors::settings` | Application and user settings validation | OCR configuration, preferences, validation | `SETTINGS_INVALID_LANGUAGE`, `SETTINGS_VALUE_OUT_OF_RANGE`, `SETTINGS_READ_ONLY` | 400, 403, 404 |
| **SearchError** | `errors::search` | Document search and indexing operations | Search queries, index operations, result processing | `SEARCH_QUERY_TOO_SHORT`, `SEARCH_INDEX_UNAVAILABLE`, `SEARCH_TOO_MANY_RESULTS` | 400, 503, 429 |
| **OcrError** | `ocr::error` | OCR processing operations | Tesseract operations, image processing, language detection | `OCR_NOT_INSTALLED`, `OCR_LANG_MISSING`, `OCR_TIMEOUT` | 400, 500, 503 |
| **DocumentError** | `routes::documents::crud` | Document CRUD operations | File upload, download, metadata operations | `DOCUMENT_NOT_FOUND`, `DOCUMENT_TOO_LARGE` | 400, 404, 413, 500 |

### Error Type Usage Guidelines

#### **ApiError** - Generic API Errors
- **Use when**: No specific error type applies
- **Best for**: Cross-cutting concerns, middleware errors, generic validation
- **Avoid when**: Domain-specific operations have dedicated error types
- **Example**: Request rate limiting, malformed JSON, generic server failures

#### **UserError** - User Management
- **Use when**: Operations involve user accounts, authentication, or authorization
- **Best for**: Registration, login, profile management, role/permission checks
- **Covers**: Account creation, credential validation, access control
- **Example**: Duplicate usernames, invalid passwords, insufficient permissions

#### **SourceError** - File Sources
- **Use when**: Operations involve external file sources (WebDAV, S3, etc.)
- **Best for**: Source configuration, sync operations, connection management
- **Covers**: Authentication to external systems, network connectivity, sync status
- **Example**: WebDAV connection failures, S3 credential issues, sync conflicts

#### **LabelError** - Label Management
- **Use when**: Operations involve document labels or label management
- **Best for**: Label CRUD operations, label assignment to documents
- **Covers**: Label validation, system label protection, usage tracking
- **Example**: Duplicate label names, modifying system labels, deleting used labels

#### **SettingsError** - Configuration & Settings
- **Use when**: Operations involve application or user settings
- **Best for**: Configuration validation, preference management, OCR settings
- **Covers**: Value validation, constraint checking, read-only setting protection
- **Example**: Invalid OCR languages, out-of-range values, conflicting settings

#### **SearchError** - Search Operations
- **Use when**: Operations involve document search or search index management
- **Best for**: Query validation, index operations, result processing
- **Covers**: Query syntax, performance limits, index availability
- **Example**: Short queries, syntax errors, index rebuilding, too many results

#### **OcrError** - OCR Processing
- **Use when**: Operations involve OCR processing with Tesseract
- **Best for**: OCR-specific failures, Tesseract configuration issues
- **Covers**: Installation checks, language data, processing errors
- **Example**: Missing Tesseract, language data not found, processing timeouts

#### **DocumentError** - Document Operations
- **Use when**: Operations involve document CRUD operations
- **Best for**: File upload/download, document metadata, storage operations
- **Covers**: File validation, storage limits, document lifecycle
- **Example**: File too large, unsupported format, document not found

### Error Severity Mapping

| Error Type | Typical Severity | Reasoning |
|------------|------------------|-----------|
| **ApiError** | Minor to Critical | Depends on specific error - server errors are Critical, validation is Minor |
| **UserError** | Minor to Important | Auth failures are Important, validation errors are Minor |
| **SourceError** | Minor to Important | Connection issues are Important, config errors are Minor |
| **LabelError** | Minor | Usually user input validation, rarely system-critical |
| **SettingsError** | Minor | Configuration errors, typically user-correctable |
| **SearchError** | Minor to Important | Index unavailable is Important, query errors are Minor |
| **OcrError** | Minor to Critical | Missing installation is Critical, processing errors are Minor |
| **DocumentError** | Minor to Important | Storage failures are Important, validation is Minor |

### Error Type Decision Tree

Use this decision tree to choose the appropriate error type:

```
Is this a user account/authentication operation?
├─ YES → UserError
└─ NO → Is this a file source operation (WebDAV, S3, Local)?
    ├─ YES → SourceError  
    └─ NO → Is this a search/indexing operation?
        ├─ YES → SearchError
        └─ NO → Is this an OCR/Tesseract operation?
            ├─ YES → OcrError
            └─ NO → Is this a document upload/download/CRUD operation?
                ├─ YES → DocumentError
                └─ NO → Is this a label management operation?
                    ├─ YES → LabelError
                    └─ NO → Is this a settings/configuration operation?
                        ├─ YES → SettingsError
                        └─ NO → Use ApiError for generic cases
```

### Quick Reference Checklist

**Before choosing an error type, ask:**

- [ ] Does the operation primarily involve user accounts, roles, or authentication? → **UserError**
- [ ] Does the operation connect to external file sources? → **SourceError** 
- [ ] Does the operation search documents or manage search index? → **SearchError**
- [ ] Does the operation use Tesseract for OCR processing? → **OcrError**
- [ ] Does the operation upload, download, or manage document files? → **DocumentError**
- [ ] Does the operation create, modify, or assign labels? → **LabelError**
- [ ] Does the operation validate or modify application settings? → **SettingsError**
- [ ] None of the above apply? → **ApiError**

### Common Error Mapping Patterns

| Operation Type | Recommended Error Type | Example Operations |
|----------------|----------------------|-------------------|
| User registration/login | UserError | `/api/auth/register`, `/api/auth/login` |
| File source sync | SourceError | `/api/sources/{id}/sync`, `/api/sources/{id}/test` |
| Document search | SearchError | `/api/search`, `/api/documents/search` |
| OCR processing | OcrError | `/api/documents/{id}/ocr`, `/api/ocr/languages` |
| Document management | DocumentError | `/api/documents`, `/api/documents/{id}` |
| Label operations | LabelError | `/api/labels`, `/api/documents/{id}/labels` |
| Settings management | SettingsError | `/api/settings`, `/api/users/{id}/settings` |
| Generic API operations | ApiError | Rate limiting, payload validation, CORS |

## Error Types

### UserError

Handles user management operations:

```rust
// Examples
UserError::NotFound
UserError::DuplicateUsername { username: "john_doe" }
UserError::PermissionDenied { reason: "Admin access required" }
UserError::InvalidCredentials
UserError::DeleteRestricted { id, reason: "Cannot delete your own account" }
```

**Error Codes**: `USER_NOT_FOUND`, `USER_DUPLICATE_USERNAME`, `USER_PERMISSION_DENIED`, etc.

### SourceError

Handles file source operations (WebDAV, Local Folder, S3):

```rust
// Examples  
SourceError::ConnectionFailed { details: "Network timeout" }
SourceError::InvalidPath { path: "/invalid/path" }
SourceError::AuthenticationFailed { name: "my-webdav", reason: "Invalid credentials" }
SourceError::SyncInProgress { name: "backup-source" }
SourceError::ConfigurationInvalid { details: "Missing server URL" }
```

**Error Codes**: `SOURCE_CONNECTION_FAILED`, `SOURCE_AUTH_FAILED`, `SOURCE_CONFIG_INVALID`, etc.

### LabelError

Handles label management:

```rust
// Examples
LabelError::DuplicateName { name: "Important" }
LabelError::SystemLabelModification { name: "system-label" }
LabelError::InvalidColor { color: "#gggggg" }
LabelError::LabelInUse { document_count: 42 }
LabelError::MaxLabelsReached { max_labels: 100 }
```

**Error Codes**: `LABEL_DUPLICATE_NAME`, `LABEL_SYSTEM_MODIFICATION`, `LABEL_IN_USE`, etc.

### SettingsError

Handles settings validation and management:

```rust
// Examples
SettingsError::InvalidLanguage { language: "xx", available_languages: "en,es,fr" }
SettingsError::ValueOutOfRange { setting_name: "timeout", value: 3600, min: 1, max: 300 }
SettingsError::InvalidOcrConfiguration { details: "DPI too high" }
SettingsError::ConflictingSettings { setting1: "auto_detect", setting2: "fixed_language" }
```

**Error Codes**: `SETTINGS_INVALID_LANGUAGE`, `SETTINGS_VALUE_OUT_OF_RANGE`, etc.

### SearchError

Handles search operations:

```rust
// Examples
SearchError::QueryTooShort { length: 1, min_length: 2 }
SearchError::TooManyResults { result_count: 15000, max_results: 10000 }
SearchError::IndexUnavailable { reason: "Rebuilding index" }
SearchError::InvalidPagination { offset: -1, limit: 0 }
```

**Error Codes**: `SEARCH_QUERY_TOO_SHORT`, `SEARCH_TOO_MANY_RESULTS`, etc.

## Integration Features

### Error Management System

All errors automatically integrate with the sophisticated error management system in `src/monitoring/error_management.rs`:

- **Categorization**: Errors are categorized (Auth, Database, Network, etc.)
- **Severity Levels**: Critical, Important, Minor, Expected
- **Intelligent Suppression**: Prevents spam from repeated errors
- **Structured Logging**: Consistent log format with context

### HTTP Response Format

All errors return consistent JSON responses:

```json
{
  "error": "User-friendly error message",
  "code": "ERROR_CODE_FOR_FRONTEND", 
  "status": 400
}
```

### Frontend Error Codes

Each error provides a stable error code for frontend handling:

```typescript
// Frontend can handle specific errors
switch (error.code) {
  case 'USER_DUPLICATE_USERNAME':
    showUsernameAlreadyExistsMessage();
    break;
  case 'SOURCE_CONNECTION_FAILED':
    showNetworkErrorDialog();
    break;
  case 'SEARCH_QUERY_TOO_SHORT':
    highlightSearchInput();
    break;
}
```

## Usage Examples

### In Route Handlers

```rust
use crate::errors::user::UserError;

async fn create_user(
    auth_user: AuthUser,
    State(state): State<Arc<AppState>>,
    Json(user_data): Json<CreateUser>,
) -> Result<Json<UserResponse>, UserError> {
    require_admin(&auth_user)?;
    
    let user = state
        .db
        .create_user(user_data)
        .await
        .map_err(|e| {
            let error_msg = e.to_string();
            if error_msg.contains("username") && error_msg.contains("unique") {
                UserError::duplicate_username(&user_data.username)
            } else if error_msg.contains("email") && error_msg.contains("unique") {
                UserError::duplicate_email(&user_data.email)
            } else {
                UserError::internal_server_error(format!("Database error: {}", e))
            }
        })?;

    Ok(Json(user.into()))
}
```

### Convenience Methods

All error types provide convenience constructors:

```rust
// Instead of verbose enum construction
UserError::DuplicateUsername { username: username.clone() }

// Use convenience methods
UserError::duplicate_username(&username)
UserError::permission_denied("Admin access required")
UserError::not_found_by_id(user_id)
```

### Error Context and Suggestions

Errors include contextual information and recovery suggestions:

```rust
LabelError::invalid_color("#gggggg") 
// Returns: "Invalid color format - use hex format like #0969da"
// Suggestion: "Use a valid hex color format like #0969da or #ff5722"

SourceError::rate_limit_exceeded("my-source", 300)
// Returns: "Rate limit exceeded, try again in 300 seconds" 
// Suggestion: "Wait 300 seconds before retrying"
```

## Best Practices

### 1. Use Specific Error Types

```rust
// Good
return Err(UserError::duplicate_username(&username));

// Avoid
return Err(UserError::BadRequest { message: "Username exists".to_string() });
```

### 2. Provide Context

```rust
// Good
SourceError::connection_failed(format!("Failed to connect to {}: {}", url, e))

// Less helpful
SourceError::connection_failed("Connection failed")
```

### 3. Handle Database Errors Thoughtfully

```rust
.map_err(|e| {
    let error_msg = e.to_string();
    if error_msg.contains("unique constraint") {
        UserError::duplicate_username(&username)
    } else if error_msg.contains("not found") {
        UserError::not_found()
    } else {
        UserError::internal_server_error(format!("Database error: {}", e))
    }
})?
```

### 4. Use Suppression Keys Wisely

```rust
impl AppError for SearchError {
    fn suppression_key(&self) -> Option<String> {
        match self {
            // Suppress repeated "no results" errors
            SearchError::NoResults => Some("search_no_results".to_string()),
            // Don't suppress validation errors - users need to see them
            SearchError::QueryTooShort { .. } => None,
            // Suppress by specific source for connection errors
            SearchError::IndexUnavailable { .. } => Some("search_index_unavailable".to_string()),
            _ => None,
        }
    }
}
```

## Migration from Generic Errors

When updating existing endpoints:

1. **Add error type import**:
   ```rust
   use crate::errors::user::UserError;
   ```

2. **Update function signature**:
   ```rust
   // Before
   async fn my_handler() -> Result<Json<Response>, StatusCode>
   
   // After  
   async fn my_handler() -> Result<Json<Response>, UserError>
   ```

**Replace generic error mapping:** Replace basic HTTP status codes with structured error responses.
   ```rust
   // Before
   .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?
   
   // After
   .map_err(|e| UserError::internal_server_error(format!("Operation failed: {}", e)))?
   ```

**Update tests:** Modify existing tests to expect the new structured error format instead of simple status codes.
   ```rust
   // Before
   assert_eq!(response.status(), StatusCode::CONFLICT);
   
   // After - check JSON response
   let error: serde_json::Value = response.json().await;
   assert_eq!(error["code"], "USER_DELETE_RESTRICTED");
   ```

## Testing

The error system includes comprehensive testing to ensure:

- Correct HTTP status codes
- Proper JSON response format  
- Error code consistency
- Integration with error management
- Suppression behavior

Run error-specific tests:
```bash
cargo test user_error
cargo test source_error  
cargo test error_integration
```

## Error Code Conventions

All error types follow consistent naming conventions for error codes:

### Naming Pattern
```
{TYPE}_{SPECIFIC_ERROR}
```

### Examples by Type
| Error Type | Prefix | Example Codes |
|------------|--------|---------------|
| **ApiError** | None | `BAD_REQUEST`, `NOT_FOUND`, `UNAUTHORIZED` |
| **UserError** | `USER_` | `USER_NOT_FOUND`, `USER_DUPLICATE_USERNAME`, `USER_PERMISSION_DENIED` |
| **SourceError** | `SOURCE_` | `SOURCE_CONNECTION_FAILED`, `SOURCE_AUTH_FAILED`, `SOURCE_CONFIG_INVALID` |
| **LabelError** | `LABEL_` | `LABEL_DUPLICATE_NAME`, `LABEL_IN_USE`, `LABEL_SYSTEM_MODIFICATION` |
| **SettingsError** | `SETTINGS_` | `SETTINGS_INVALID_LANGUAGE`, `SETTINGS_VALUE_OUT_OF_RANGE` |
| **SearchError** | `SEARCH_` | `SEARCH_QUERY_TOO_SHORT`, `SEARCH_INDEX_UNAVAILABLE` |
| **OcrError** | `OCR_` | `OCR_NOT_INSTALLED`, `OCR_LANG_MISSING`, `OCR_TIMEOUT` |
| **DocumentError** | `DOCUMENT_` | `DOCUMENT_NOT_FOUND`, `DOCUMENT_TOO_LARGE` |

### Code Style Guidelines
- Use `SCREAMING_SNAKE_CASE` for all error codes
- Start with error type prefix (except ApiError)
- Be descriptive but concise
- Avoid abbreviations unless commonly understood
- Group related errors with consistent sub-prefixes

## Practical Examples

### Complete Implementation Examples

#### User Registration Endpoint
```rust
use crate::errors::user::UserError;

async fn register_user(
    State(state): State<Arc<AppState>>,
    Json(user_data): Json<CreateUser>,
) -> Result<Json<UserResponse>, UserError> {
    // Validate input
    if user_data.username.len() < 3 {
        return Err(UserError::invalid_username(
            &user_data.username, 
            "Username must be at least 3 characters"
        ));
    }
    
    // Create user
    let user = state.db.create_user(user_data).await
        .map_err(|e| {
            let error_msg = e.to_string();
            if error_msg.contains("username") && error_msg.contains("unique") {
                UserError::duplicate_username(&user_data.username)
            } else if error_msg.contains("email") && error_msg.contains("unique") {
                UserError::duplicate_email(&user_data.email)
            } else {
                UserError::internal_server_error(format!("Database error: {}", e))
            }
        })?;

    Ok(Json(user.into()))
}
```

#### WebDAV Source Test Endpoint
```rust
use crate::errors::source::SourceError;

async fn test_webdav_connection(
    State(state): State<Arc<AppState>>,
    Path(source_id): Path<Uuid>,
    auth_user: AuthUser,
) -> Result<Json<ConnectionTestResponse>, SourceError> {
    let source = state.db.get_source(source_id).await
        .map_err(|_| SourceError::not_found_by_id(source_id))?;
    
    // Check ownership
    if source.user_id != auth_user.user.id {
        return Err(SourceError::permission_denied(
            "You can only test your own sources"
        ));
    }
    
    // Test connection
    match test_webdav_connection_internal(&source).await {
        Ok(()) => Ok(Json(ConnectionTestResponse { success: true })),
        Err(e) if e.to_string().contains("authentication") => {
            Err(SourceError::authentication_failed(&source.name, &e.to_string()))
        },
        Err(e) if e.to_string().contains("timeout") => {
            Err(SourceError::network_timeout(&source.url, 30))
        },
        Err(e) => {
            Err(SourceError::connection_failed(format!("Connection test failed: {}", e)))
        }
    }
}
```

#### Search Query Endpoint
```rust
use crate::errors::search::SearchError;

async fn search_documents(
    State(state): State<Arc<AppState>>,
    Query(params): Query<SearchParams>,
    auth_user: AuthUser,
) -> Result<Json<SearchResponse>, SearchError> {
    // Validate query length
    if params.query.len() < 2 {
        return Err(SearchError::query_too_short(params.query.len(), 2));
    }
    
    if params.query.len() > 500 {
        return Err(SearchError::query_too_long(params.query.len(), 500));
    }
    
    // Check pagination
    if params.limit > 1000 {
        return Err(SearchError::invalid_pagination(params.offset, params.limit));
    }
    
    // Perform search
    let results = state.search_service.search(&params, auth_user.user.id).await
        .map_err(|e| match e {
            SearchServiceError::IndexUnavailable => {
                SearchError::index_unavailable("Search index is being rebuilt")
            },
            SearchServiceError::TooManyResults(count) => {
                SearchError::too_many_results(count, 10000)
            },
            SearchServiceError::InvalidSyntax(details) => {
                SearchError::invalid_syntax(details)
            },
            _ => SearchError::internal_error(format!("Search failed: {}", e)),
        })?;
    
    Ok(Json(results))
}
```

## Monitoring

Error metrics are automatically tracked:

- **Error rates** by type and endpoint
- **Suppression statistics** for repeated errors
- **Severity distribution** across the application
- **Recovery suggestions** utilization

View error dashboards in Grafana or check Prometheus metrics at `/metrics`.

## Future Enhancements

Planned improvements to the error system:

1. **Internationalization** - Multi-language error messages
2. **Error Analytics** - Advanced error pattern detection  
3. **Auto-Recovery** - Suggested API retry strategies
4. **Enhanced Suppression** - Time-based and pattern-based suppression
5. **Error Documentation** - Auto-generated API error documentation

## References

- [API Reference](../api-reference.md)