# Error Handling System - Developer Documentation **Version:** 1.0.0 **Last Updated:** 2025 **Status:** Phase 1 Complete (Admin), Phase 2-3 Pending (Store, Storefront) --- ## Table of Contents 1. [Overview](#overview) 2. [Architecture](#architecture) 3. [System Components](#system-components) 4. [Context Detection](#context-detection) 5. [Error Response Types](#error-response-types) 6. [Template System](#template-system) 7. [Implementation Status](#implementation-status) 8. [Developer Guidelines](#developer-guidelines) 9. [Adding New Error Pages](#adding-new-error-pages) 10. [Testing Guide](#testing-guide) 11. [Troubleshooting](#troubleshooting) 12. [API Reference](#api-reference) --- ## Overview ### Purpose The error handling system provides context-aware error responses throughout the application. It automatically determines whether to return JSON (for API calls) or HTML error pages (for browser requests), and renders appropriate error pages based on the request context (Admin, Store Dashboard, or Storefront). ### Key Features - **Context-Aware**: Different error pages for Admin, Store, and Storefront areas - **Automatic Detection**: Distinguishes between API and HTML page requests - **Consistent JSON API**: API endpoints always return standardized JSON errors - **Fallback Mechanism**: Gracefully handles missing templates - **Debug Mode**: Shows technical details to admin users only - **Theme Integration**: Storefront error pages support store theming (Phase 3) - **Security**: 401 errors automatically redirect to appropriate login pages ### Design Principles 1. **Separation of Concerns**: HTML templates are separate from exception handler logic 2. **Fail-Safe**: Multiple fallback levels ensure errors always render 3. **Developer-Friendly**: Easy to add new error pages or contexts 4. **User-Centric**: Professional error pages with clear messaging and actions 5. **Secure**: Technical details hidden from non-admin users --- ## Architecture ### Request Flow ``` HTTP Request ↓ Store Context Middleware (detects store from domain/subdomain/path) ↓ Context Detection Middleware (detects API/Admin/Store/Storefront) ↓ Route Handler (processes request, may throw exception) ↓ Exception Handler (catches and processes exception) ↓ ├─→ API Request? → Return JSON Response ├─→ HTML Request + 401? → Redirect to Login └─→ HTML Request? → Render Context-Aware Error Page ``` ### Components ``` middleware/ ├── store_context.py # Detects store from URL (existing) └── context_middleware.py # Detects request context type (NEW) app/exceptions/ ├── handler.py # Exception handlers (refactored) ├── error_renderer.py # Error page rendering logic (NEW) └── base.py # Base exception classes (existing) app/templates/ ├── admin/errors/ # Admin error pages (Phase 1 - COMPLETE) ├── store/errors/ # Store error pages (Phase 2 - PENDING) ├── storefront/errors/ # Storefront error pages (Phase 3 - PENDING) └── shared/ # Shared fallback error pages (COMPLETE) ``` --- ## System Components ### 1. Context Detection Middleware **File:** `middleware/context_middleware.py` **Purpose:** Detects the request context type and injects it into `request.state.context_type`. **Context Types:** ```python class RequestContext(str, Enum): API = "api" # API endpoints (/api/*) ADMIN = "admin" # Admin portal (/admin/* or admin.*) STORE_DASHBOARD = "store" # Store management (/store/*) SHOP = "shop" # Customer storefront (store subdomains) FALLBACK = "fallback" # Unknown/generic context ``` **Detection Logic:** 1. **API** - Path starts with `/api/` (highest priority) 2. **ADMIN** - Path starts with `/admin` or host starts with `admin.` 3. **STORE_DASHBOARD** - Path starts with `/store/` 4. **SHOP** - `request.state.store` exists (set by store_context_middleware) 5. **FALLBACK** - None of the above match **Usage:** ```python from middleware.frontend_type import get_frontend_type from app.modules.enums import FrontendType def my_handler(request: Request): frontend_type = get_frontend_type(request) if frontend_type == FrontendType.ADMIN: # Handle admin-specific logic pass ``` ### 2. Error Page Renderer **File:** `app/exceptions/error_renderer.py` **Purpose:** Renders context-aware HTML error pages using Jinja2 templates. **Key Methods:** ```python ErrorPageRenderer.render_error_page( request: Request, status_code: int, error_code: str, message: str, details: Optional[Dict[str, Any]] = None, show_debug: bool = False, ) -> HTMLResponse ``` **Template Selection Priority:** 1. `{context}/errors/{status_code}.html` (e.g., `admin/errors/404.html`) 2. `{context}/errors/generic.html` (e.g., `admin/errors/generic.html`) 3. `shared/{status_code}-fallback.html` (e.g., `shared/404-fallback.html`) 4. `shared/generic-fallback.html` (absolute fallback) **Template Variables Provided:** ```python { "status_code": int, # HTTP status code "status_name": str, # Friendly name ("Not Found") "error_code": str, # Application error code "message": str, # User-friendly message "details": dict, # Additional error details "show_debug": bool, # Whether to show debug info "context_type": str, # Request context type "path": str, # Request path "store": dict, # Store info (storefront context only) "theme": dict, # Theme data (storefront context only) } ``` ### 3. Exception Handler **File:** `app/exceptions/handler.py` **Purpose:** Central exception handling for all application exceptions. **Handlers:** - `OrionException` - Custom application exceptions - `HTTPException` - FastAPI HTTP exceptions - `RequestValidationError` - Pydantic validation errors - `Exception` - Generic Python exceptions - `404` - Not Found errors **Response Logic:** ```python if request.url.path.startswith("/api/"): return JSONResponse(...) # Always JSON for API elif _is_html_page_request(request): if status_code == 401: return RedirectResponse(...) # Redirect to login else: return ErrorPageRenderer.render_error_page(...) # HTML error page else: return JSONResponse(...) # Default to JSON ``` --- ## Context Detection ### How Context is Determined The system uses a priority-based approach to detect context: ```python # Priority 1: API Context if path.startswith("/api/"): return RequestContext.API # Priority 2: Admin Context if path.startswith("/admin") or host.startswith("admin."): return RequestContext.ADMIN # Priority 3: Store Dashboard Context if path.startswith("/store/"): return RequestContext.STORE_DASHBOARD # Priority 4: Storefront Context if hasattr(request.state, 'store') and request.state.store: return RequestContext.SHOP # Priority 5: Fallback return RequestContext.FALLBACK ``` ### Context Examples | URL | Host | Context | |-----|------|---------| | `/api/v1/admin/stores` | any | API | | `/admin/dashboard` | any | ADMIN | | `/store/products` | any | STORE_DASHBOARD | | `/products` | `store1.platform.com` | SHOP | | `/products` | `customdomain.com` | SHOP (if store detected) | | `/about` | `platform.com` | FALLBACK | ### Special Cases **Admin Access via Subdomain:** ``` admin.platform.com/dashboard → ADMIN context ``` **Store Dashboard Access:** ``` /store/store1/dashboard → STORE_DASHBOARD context store1.platform.com/store/dashboard → STORE_DASHBOARD context ``` **Storefront Access:** ``` store1.platform.com/ → SHOP context customdomain.com/ → SHOP context (if store verified) ``` --- ## Error Response Types ### 1. JSON Responses (API Context) **When:** Request path starts with `/api/` **Format:** ```json { "error_code": "STORE_NOT_FOUND", "message": "Store with ID '999' not found", "status_code": 404, "details": { "store_id": "999" } } ``` **Always JSON, Regardless of Accept Header:** API endpoints MUST always return JSON, even if the client sends `Accept: text/html`. ### 2. HTML Error Pages (HTML Page Requests) **When:** - NOT an API request - GET request - Accept header includes `text/html` - NOT already on login page **Renders:** Context-appropriate HTML error page **Example:** Admin 404 ```html 404 - Page Not Found | Admin Portal

404

The admin page you're looking for doesn't exist.

Go to Dashboard
``` ### 3. Login Redirects (401 Unauthorized) **When:** - HTML page request - 401 status code **Behavior:** Redirect to appropriate login page based on context | Context | Redirect To | |---------|-------------| | ADMIN | `/admin/login` | | STORE_DASHBOARD | `/store/login` | | SHOP | `/storefront/login` | | FALLBACK | `/admin/login` | --- ## Template System ### Template Structure All error templates follow this organization: ``` app/templates/ ├── admin/ │ └── errors/ │ ├── base.html # Base template (extends nothing) │ ├── 400.html # Bad Request │ ├── 401.html # Unauthorized │ ├── 403.html # Forbidden │ ├── 404.html # Not Found │ ├── 422.html # Validation Error │ ├── 429.html # Rate Limit │ ├── 500.html # Internal Server Error │ ├── 502.html # Bad Gateway │ └── generic.html # Catch-all │ ├── store/ │ └── errors/ │ └── (same structure as admin) │ ├── storefront/ │ └── errors/ │ └── (same structure as admin) │ └── shared/ ├── 404-fallback.html ├── 500-fallback.html ├── generic-fallback.html └── cdn-fallback.html ``` ### Base Template Pattern Each context has its own `base.html` template: ```html {% block title %}{{ status_code }} - {{ status_name }}{% endblock %}
{% block content %} {% endblock %}
``` ### Specific Error Template Pattern ```html {% extends "admin/errors/base.html" %} {% block icon %}🔍{% endblock %} {% block title %}404 - Page Not Found{% endblock %} {% block content %}
🔍
404
Page Not Found
The admin page you're looking for doesn't exist or has been moved.
Error Code: {{ error_code }}
Go to Dashboard Go Back
{% if show_debug %}
{% endif %} {% endblock %} ``` ### Context-Specific Considerations #### Admin Error Pages **Purpose:** Error pages for platform administrators **Characteristics:** - Professional platform branding - Links to admin dashboard - Full debug information when appropriate - Support contact link **Action Buttons:** - Primary: "Go to Dashboard" → `/admin/dashboard` - Secondary: "Go Back" → `javascript:history.back()` #### Store Error Pages **Purpose:** Error pages for store dashboard users **Characteristics:** - Professional store management branding - Links to store dashboard - Debug information for store admins - Store support contact link **Action Buttons:** - Primary: "Go to Dashboard" → `/store/dashboard` - Secondary: "Go Back" → `javascript:history.back()` #### Storefront Error Pages **Purpose:** Error pages for customers on store storefronts **Characteristics:** - **Uses store theme** (colors, logo, fonts) - Customer-friendly language - No technical jargon - Links to storefront homepage - Customer support contact **Action Buttons:** - Primary: "Continue Shopping" → Storefront homepage - Secondary: "Contact Support" → Store support page **Theme Integration:** ```html ``` --- ## Implementation Status ### Phase 1: Admin Error Handling ✅ COMPLETE **Status:** Fully implemented and ready for use **Components:** - ✅ Context detection middleware - ✅ Error page renderer - ✅ Refactored exception handler - ✅ Admin error templates (11 files) - ✅ Fallback templates (3 files) **Error Codes Implemented:** - ✅ 400 (Bad Request) - ✅ 401 (Unauthorized) - ✅ 403 (Forbidden) - ✅ 404 (Not Found) - ✅ 422 (Validation Error) - ✅ 429 (Rate Limit) - ✅ 500 (Internal Server Error) - ✅ 502 (Bad Gateway) - ✅ Generic (Catch-all) ### Phase 2: Store Error Handling ⏳ PENDING **Status:** Not yet implemented **Required Tasks:** 1. Create `/app/templates/store/errors/` directory 2. Copy admin templates as starting point 3. Customize messaging for store context: - Change "Admin Portal" to "Store Portal" - Update dashboard links to `/store/dashboard` - Adjust support links to store support 4. Update action button destinations 5. Test all error codes in store context **Estimated Effort:** 1-2 hours **Priority:** Medium (stores currently see fallback pages) ### Phase 3: Storefront Error Handling ⏳ PENDING **Status:** Not yet implemented **Required Tasks:** 1. Create `/app/templates/storefront/errors/` directory 2. Create customer-facing error templates: - Use customer-friendly language - Integrate store theme variables - Add store logo/branding 3. Update ErrorPageRenderer to pass theme data 4. Implement theme integration: ```python if context_type == RequestContext.SHOP: template_data["theme"] = request.state.theme template_data["store"] = request.state.store ``` 5. Test with multiple store themes 6. Test on custom domains **Estimated Effort:** 2-3 hours **Priority:** High (customers currently see non-branded fallback pages) **Dependencies:** Requires store theme system (already exists) --- ## Developer Guidelines ### When to Throw Exceptions **Use Custom Exceptions:** ```python from app.exceptions import StoreNotFoundException # Good - Specific exception raise StoreNotFoundException(store_id="123") # Avoid - Generic exception with less context raise HTTPException(status_code=404, detail="Store not found") ``` **Exception Selection Guide:** | Scenario | Exception | Status Code | |----------|-----------|-------------| | Resource not found | `{Resource}NotFoundException` | 404 | | Validation failed | `ValidationException` | 422 | | Unauthorized | `AuthenticationException` | 401 | | Forbidden | `AuthorizationException` | 403 | | Business rule violated | `BusinessLogicException` | 400 | | External service failed | `ExternalServiceException` | 502 | | Rate limit exceeded | `RateLimitException` | 429 | ### Creating Custom Exceptions Follow this pattern: ```python # app/exceptions/my_domain.py from .base import ResourceNotFoundException class MyResourceNotFoundException(ResourceNotFoundException): """Raised when MyResource is not found.""" def __init__(self, resource_id: str): super().__init__( resource_type="MyResource", identifier=resource_id, message=f"MyResource with ID '{resource_id}' not found", error_code="MY_RESOURCE_NOT_FOUND", ) ``` Then register in `app/exceptions/__init__.py`: ```python from .my_domain import MyResourceNotFoundException __all__ = [ # ... existing exports "MyResourceNotFoundException", ] ``` ### Error Messages Best Practices **User-Facing Messages:** - Clear and concise - Avoid technical jargon - Suggest next actions - Never expose sensitive information ```python # Good message="The product you're looking for is currently unavailable." # Bad message="SELECT * FROM products WHERE id=123 returned 0 rows" ``` **Error Codes:** - Use UPPER_SNAKE_CASE - Be descriptive but concise - Follow existing patterns ```python # Good error_code="PRODUCT_OUT_OF_STOCK" error_code="PAYMENT_PROCESSING_FAILED" # Bad error_code="error1" error_code="ProductOutOfStockException" ``` ### Details Dictionary Use the `details` dictionary for additional context: ```python raise StoreNotFoundException( store_id="123" ) # Results in: # details = {"store_id": "123", "resource_type": "Store"} # For validation errors: raise ValidationException( message="Invalid email format", field="email", details={ "provided_value": user_input, "expected_format": "user@example.com" } ) ``` **What to Include in Details:** - ✅ Resource identifiers - ✅ Validation error specifics - ✅ Operation context - ✅ Non-sensitive debugging info - ❌ Passwords or secrets - ❌ Internal system paths - ❌ Database queries - ❌ Stack traces (use show_debug instead) --- ## Adding New Error Pages ### Step 1: Identify Context Determine which context needs the new error page: - Admin Portal → `admin/errors/` - Store Dashboard → `store/errors/` - Customer Storefront → `storefront/errors/` ### Step 2: Choose Template Type **Specific Error Code Template:** - For common HTTP status codes (400, 403, 404, 500, etc.) - File name: `{status_code}.html` **Generic Catch-All Template:** - For less common or custom error codes - File name: `generic.html` - Uses variables to display appropriate content ### Step 3: Create Template **Option A: Extend Base Template** (Recommended) ```html {% extends "admin/errors/base.html" %} {% block icon %}🔧{% endblock %} {% block title %}503 - Service Unavailable{% endblock %} {% block content %}
🔧
503
Service Unavailable
The service is temporarily unavailable. We're working to restore it.
Error Code: {{ error_code }}
Retry Dashboard
{% if show_debug %}

🔧 Debug Information (Admin Only)

Path: {{ path }}
{% if details %}
Details:
{{ details | tojson(indent=2) }}
{% endif %}
{% endif %} {% endblock %} ``` **Option B: Standalone Template** (For custom designs) ```html {{ status_code }} - {{ status_name }} ``` ### Step 4: Add to ErrorPageRenderer (if needed) If adding a new status code with a friendly name: ```python # app/exceptions/error_renderer.py STATUS_CODE_NAMES = { # ... existing codes 503: "Service Unavailable", # Add new code } STATUS_CODE_MESSAGES = { # ... existing messages 503: "The service is temporarily unavailable. Please try again later.", } ``` ### Step 5: Test ```bash # Test the new error page curl -H "Accept: text/html" http://localhost:8000/admin/test-503 # Or trigger programmatically: from app.exceptions import ServiceUnavailableException raise ServiceUnavailableException("Maintenance in progress") ``` --- ## Testing Guide ### Unit Tests **Test Context Detection:** ```python # tests/test_frontend_detector.py from app.core.frontend_detector import FrontendDetector from app.modules.enums import FrontendType def test_admin_detection(): assert FrontendDetector.is_admin("localhost", "/admin/dashboard") is True def test_storefront_detection(): frontend_type = FrontendDetector.detect( host="localhost", path="/storefront/products", has_store_context=True ) assert frontend_type == FrontendType.STOREFRONT ``` **Test Error Renderer:** ```python # tests/test_error_renderer.py from app.exceptions.error_renderer import ErrorPageRenderer def test_template_selection_admin(): template = ErrorPageRenderer._find_template( context_type=RequestContext.ADMIN, status_code=404 ) assert template == "admin/errors/404.html" def test_template_fallback(): template = ErrorPageRenderer._find_template( context_type=RequestContext.ADMIN, status_code=999 # Non-existent error code ) assert template == "admin/errors/generic.html" ``` **Test Exception Handlers:** ```python # tests/test_exception_handlers.py from fastapi.testclient import TestClient def test_api_returns_json(client: TestClient): response = client.get("/api/v1/nonexistent") assert response.status_code == 404 assert response.headers["content-type"] == "application/json" data = response.json() assert "error_code" in data assert "message" in data def test_html_page_returns_html(client: TestClient): response = client.get( "/admin/nonexistent", headers={"Accept": "text/html"} ) assert response.status_code == 404 assert "text/html" in response.headers["content-type"] assert " bool: return request.url.path.startswith("/api/") # Must have leading slash ``` ### Issue: HTML Pages Returning JSON **Symptoms:** Browser shows JSON instead of error page when visiting `/admin/nonexistent` **Diagnosis:** Check Accept header: ```python # Add logging logger.debug(f"Accept: {request.headers.get('accept', '')}") logger.debug(f"is_html: {_is_html_page_request(request)}") ``` **Common Causes:** 1. Browser not sending `Accept: text/html` 2. Request is POST/PUT/DELETE (not GET) 3. Path is `/api/*` 4. Already on login page **Solution:** Verify `_is_html_page_request()` logic: ```python def _is_html_page_request(request: Request) -> bool: if _is_api_request(request): return False if request.url.path.endswith("/login"): return False if request.method != "GET": return False accept_header = request.headers.get("accept", "") if "text/html" not in accept_header: return False return True ``` ### Issue: Template Not Found Error **Symptoms:** ``` jinja2.exceptions.TemplateNotFound: admin/errors/404.html ``` **Diagnosis:** 1. Check template file exists: ```bash ls -la app/templates/admin/errors/404.html ``` 2. Check templates directory configuration in main.py: ```python # Should be: TEMPLATES_DIR = BASE_DIR / "app" / "templates" templates = Jinja2Templates(directory=str(TEMPLATES_DIR)) ``` **Solution:** - Ensure template files are in correct location - Verify templates directory path is correct - Check file permissions ### Issue: Wrong Context Detected **Symptoms:** Admin page shows storefront error page, or vice versa **Diagnosis:** Add context logging: ```python # In context_middleware.py logger.info( f"Context detection: path={request.url.path}, " f"host={request.headers.get('host')}, " f"context={context_type}" ) ``` **Solution:** Check middleware order in `main.py`: ```python # Correct order: app.middleware("http")(store_context_middleware) # FIRST app.middleware("http")(context_middleware) # SECOND ``` ### Issue: Debug Info Not Showing for Admin **Symptoms:** Debug information not visible in admin error pages **Diagnosis:** Check `_is_admin_user()` implementation: ```python # In error_renderer.py @staticmethod def _is_admin_user(request: Request) -> bool: context_type = get_request_context(request) logger.debug(f"Checking admin user: context={context_type}") return context_type == RequestContext.ADMIN ``` **Solution:** - Verify context is correctly detected as ADMIN - Check `show_debug` parameter is True in render call - Ensure template has `{% if show_debug %}` block ### Issue: 401 Not Redirecting **Symptoms:** 401 errors show JSON instead of redirecting to login **Diagnosis:** Check if request is detected as HTML page request: ```python # Add logging before redirect check logger.debug( f"401 handling: is_html={_is_html_page_request(request)}, " f"path={request.url.path}, method={request.method}, " f"accept={request.headers.get('accept')}" ) ``` **Solution:** Ensure all conditions for HTML page request are met: - NOT an API endpoint - GET request - Accept header includes `text/html` - NOT already on login page ### Issue: Store Theme Not Applied to Storefront Errors **Symptoms:** Storefront error pages don't use store colors/branding (Phase 3 issue) **Diagnosis:** 1. Check if theme is in request state: ```python logger.debug(f"Theme in state: {hasattr(request.state, 'theme')}") logger.debug(f"Theme data: {getattr(request.state, 'theme', None)}") ``` 2. Check if theme is passed to template: ```python # In error_renderer.py _get_context_data() if context_type == RequestContext.SHOP: theme = getattr(request.state, "theme", None) logger.debug(f"Passing theme to template: {theme}") ``` **Solution:** - Ensure theme_context_middleware ran before error - Verify theme data structure is correct - Check template uses theme variables correctly: ```html ``` --- ## API Reference ### Frontend Type Detection #### `get_frontend_type(request: Request) -> FrontendType` Gets the frontend type for the current request. **Parameters:** - `request` (Request): FastAPI request object **Returns:** - FrontendType enum value **Example:** ```python from middleware.frontend_type import get_frontend_type from app.modules.enums import FrontendType def my_handler(request: Request): frontend_type = get_frontend_type(request) return {"frontend_type": frontend_type.value} ``` ### Error Rendering #### `ErrorPageRenderer.render_error_page(...) -> HTMLResponse` Renders context-aware HTML error page. **Parameters:** ```python request: Request # FastAPI request object status_code: int # HTTP status code error_code: str # Application error code message: str # User-friendly error message details: Optional[Dict[str, Any]] = None # Additional error details show_debug: bool = False # Whether to show debug info ``` **Returns:** - HTMLResponse with rendered error page **Example:** ```python from app.exceptions.error_renderer import ErrorPageRenderer return ErrorPageRenderer.render_error_page( request=request, status_code=404, error_code="STORE_NOT_FOUND", message="The store you're looking for doesn't exist.", details={"store_id": "123"}, show_debug=True, ) ``` #### `ErrorPageRenderer.get_templates_dir() -> Path` Gets the templates directory path. **Returns:** - Path object pointing to templates directory #### `ErrorPageRenderer._find_template(context_type, status_code) -> str` Finds appropriate error template based on context and status code. **Parameters:** - `context_type` (RequestContext): Request context type - `status_code` (int): HTTP status code **Returns:** - String path to template (e.g., "admin/errors/404.html") ### Exception Utilities #### `raise_not_found(resource_type: str, identifier: str) -> None` Convenience function to raise ResourceNotFoundException. **Example:** ```python from app.exceptions.handler import raise_not_found raise_not_found("Store", "123") # Raises: ResourceNotFoundException with appropriate message ``` #### `raise_validation_error(message: str, field: str = None, details: dict = None) -> None` Convenience function to raise ValidationException. **Example:** ```python from app.exceptions.handler import raise_validation_error raise_validation_error( message="Invalid email format", field="email", details={"provided": user_input} ) ``` #### `raise_auth_error(message: str = "Authentication failed") -> None` Convenience function to raise AuthenticationException. #### `raise_permission_error(message: str = "Access denied") -> None` Convenience function to raise AuthorizationException. --- ## Configuration ### Middleware Order **Critical:** Middleware must be registered in this exact order in `main.py`: ```python # 1. CORS (if needed) app.add_middleware(CORSMiddleware, ...) # 2. Store Context Detection (MUST BE FIRST) app.middleware("http")(store_context_middleware) # 3. Context Detection (MUST BE AFTER STORE) app.middleware("http")(context_middleware) # 4. Theme Context (MUST BE AFTER CONTEXT) app.middleware("http")(theme_context_middleware) # 5. Logging (optional, should be last) app.add_middleware(LoggingMiddleware) ``` **Why This Order Matters:** 1. Store context must set `request.state.store` first 2. Context detection needs store info to identify SHOP context 3. Theme context needs store info to load theme 4. Logging should be last to capture all middleware activity ### Template Directory Configure in `main.py`: ```python from pathlib import Path BASE_DIR = Path(__file__).resolve().parent TEMPLATES_DIR = BASE_DIR / "app" / "templates" templates = Jinja2Templates(directory=str(TEMPLATES_DIR)) ``` ### Error Code Registry Update as needed in `app/exceptions/error_renderer.py`: ```python STATUS_CODE_NAMES = { 400: "Bad Request", 401: "Unauthorized", 403: "Forbidden", 404: "Not Found", 422: "Validation Error", 429: "Too Many Requests", 500: "Internal Server Error", 502: "Bad Gateway", 503: "Service Unavailable", # Add new codes here } STATUS_CODE_MESSAGES = { 400: "The request could not be processed due to invalid data.", # ... etc } ``` --- ## Best Practices Summary ### DO: ✅ Use specific exception classes for different error scenarios ✅ Provide clear, user-friendly error messages ✅ Include relevant details in the `details` dictionary ✅ Use consistent error codes across the application ✅ Test both API and HTML responses ✅ Keep error templates simple and accessible ✅ Use debug mode responsibly (admin only) ✅ Follow the template inheritance pattern ✅ Document any new exception types ✅ Test error pages manually in browsers ### DON'T: ❌ Expose sensitive information in error messages ❌ Use generic exceptions for domain-specific errors ❌ Return HTML for API endpoints ❌ Skip the Accept header check ❌ Hardcode HTML in exception handlers ❌ Forget to add fallback templates ❌ Show technical details to customers ❌ Use complex JavaScript in error pages ❌ Forget to test 401 redirects ❌ Mix API and page response logic --- ## Support and Questions For questions or issues with the error handling system: 1. **Check Logs:** Look for `[CONTEXT]` and `[ERROR]` log messages 2. **Review This Documentation:** Most issues are covered in Troubleshooting 3. **Check Implementation Status:** Verify which phase is complete 4. **Test Locally:** Reproduce the issue with curl/browser 5. **Contact:** [Your team contact information] --- **Document Version:** 1.0.0 **Last Updated:** 2025 **Maintained By:** [Your team name] **Next Review:** After Phase 2 & 3 completion