"""Global error handling middleware.""" from fastapi import Request, HTTPException from fastapi.responses import JSONResponse from fastapi.exceptions import RequestValidationError from starlette.exceptions import HTTPException as StarletteHTTPException import logging import traceback import re logger = logging.getLogger(__name__) def redact_sensitive_data(data: str) -> str: """Redact sensitive information from logs.""" # Redact Authorization headers data = re.sub(r'(Authorization["\']?:\s*["\']?Bearer\s+)[^\s"\']+', r'\1***', data, flags=re.IGNORECASE) # Redact bearer tokens in any form data = re.sub(r'(bearer["\']?:\s*["\']?)[^\s"\']+', r'\1***', data, flags=re.IGNORECASE) # Redact JWT tokens (3 base64 parts separated by dots) data = re.sub(r'\b[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\b', '***JWT***', data) return data async def http_exception_handler(request: Request, exc: HTTPException): """Handle HTTP exceptions.""" return JSONResponse( status_code=exc.status_code, content={ "error": exc.detail, "code": f"HTTP_{exc.status_code}" } ) async def validation_exception_handler(request: Request, exc: RequestValidationError): """Handle validation errors.""" errors = [] for error in exc.errors(): field = ".".join(str(x) for x in error["loc"]) errors.append(f"{field}: {error['msg']}") return JSONResponse( status_code=422, content={ "error": "Validation failed", "details": "; ".join(errors), "code": "VALIDATION_ERROR" } ) async def general_exception_handler(request: Request, exc: Exception): """Handle unexpected exceptions.""" # Redact sensitive data from error messages and traceback error_msg = redact_sensitive_data(str(exc)) sanitized_traceback = redact_sensitive_data(traceback.format_exc()) logger.error(f"Unexpected error: {error_msg}\n{sanitized_traceback}") return JSONResponse( status_code=500, content={ "error": "Internal server error", "details": "An unexpected error occurred", "code": "INTERNAL_ERROR" } ) def register_exception_handlers(app): """Register all exception handlers with the app.""" app.add_exception_handler(HTTPException, http_exception_handler) app.add_exception_handler(RequestValidationError, validation_exception_handler) app.add_exception_handler(Exception, general_exception_handler)