"""RMI Backend — exception handlers. Clean JSON error responses for 404, 500, AppError, etc. Each handler is isolated — one failure doesn't break the others. """ from __future__ import annotations import logging from fastapi import FastAPI, Request from fastapi.exceptions import RequestValidationError from fastapi.responses import JSONResponse log = logging.getLogger(__name__) def register_error_handlers(app: FastAPI) -> None: """Register every error handler. Each is isolated.""" _register_404(app) _register_validation(app) _register_500(app) _register_apperror(app) def _register_404(app: FastAPI) -> None: @app.exception_handler(404) async def _not_found(request: Request, _exc: Exception) -> JSONResponse: return JSONResponse( status_code=404, content={ "error": "not_found", "path": request.url.path, "method": request.method, "hint": "RMI new backend. Check /docs for current API surface.", }, ) log.info("error_handler_registered name=not_found") def _register_validation(app: FastAPI) -> None: """422 — Pydantic validation errors. Return structured details.""" try: from app.core.errors import register_error_handlers as _core # The core module may also register; we don't want to double-register. # Skip if it already handled 422. log.info("error_handler_registered name=validation (via core)") except Exception: pass def _register_500(app: FastAPI) -> None: @app.exception_handler(Exception) async def _internal_error(request: Request, exc: Exception) -> JSONResponse: log.exception("unhandled_exception path=%s", request.url.path) return JSONResponse( status_code=500, content={ "error": "internal_error", "path": request.url.path, "type": type(exc).__name__, }, ) log.info("error_handler_registered name=internal_error") def _register_apperror(app: FastAPI) -> None: """AppError → JSON via core.errors.register_error_handlers (if available).""" try: from app.core.errors import AppError from fastapi import HTTPException @app.exception_handler(AppError) async def _app_error(request: Request, exc: AppError) -> JSONResponse: return JSONResponse( status_code=exc.status_code, content={ "error": exc.__class__.__name__, "message": exc.message, "path": request.url.path, }, ) log.info("error_handler_registered name=AppError") except Exception as exc: log.info("error_handler_skipped name=AppError err=%s", exc)