# Error Handling > How errors are handled in this project. --- ## Overview Backend error transport is RFC7807-style `application/problem+json` with stable `code` and optional `params` extensions. Evidence: - Error class: `backend/src/core/http/errors.py` (`ApiProblemError`) - Problem details builder: `backend/src/core/http/response.py` - Global exception mapping: `backend/src/app.py` - Error code registry: `docs/protocols/common/http-error-codes.md` --- ## Error Types ### 1) `ApiProblemError` (preferred for business/API errors) Used to carry `status_code`, `detail`, `code`, `params`. Examples: - `backend/src/v1/todo/service.py` (`_todo_error(...)` returns `ApiProblemError`) - `backend/src/v1/schedule_items/service.py` (raises `ApiProblemError` with `problem_payload(...)`) - `backend/src/v1/users/dependencies.py` (auth failures mapped to `AUTH_UNAUTHORIZED`, `JWT_VERIFIER_NOT_CONFIGURED`) ### 2) Infra/DB exceptions (caught at boundary and converted) - `SQLAlchemyError` is commonly caught in service/repository boundaries. - Many repository methods log and re-raise DB exceptions (for example in todo/schedule_items repositories); generic helpers in `core/db/base_repository.py` may just propagate exceptions. - Service layer usually maps infra failures to stable codes like `*_SERVICE_UNAVAILABLE` / `*_STORE_UNAVAILABLE`. Examples: - `backend/src/v1/todo/repository.py` - `backend/src/v1/todo/service.py` - `backend/src/v1/schedule_items/service.py` --- ## Error Handling Patterns Observed patterns: 1. **Service methods**: catch DB/infrastructure errors, rollback when needed, then raise typed API problem. - `backend/src/v1/todo/service.py` - `backend/src/v1/schedule_items/service.py` 2. **Repository methods**: log exception context and re-raise. - `backend/src/v1/todo/repository.py` - `backend/src/v1/schedule_items/repository.py` 3. **Global handlers**: convert unhandled errors and framework exceptions into problem+json responses. - `backend/src/app.py` --- ## API Error Responses Expected transport: - Media type: `application/problem+json` - Fields: RFC7807 core (`type`, `title`, `status`, `detail`, `instance`) + extension fields (`code`, `params`) Evidence: - Response builder model in `backend/src/core/http/response.py` - Exception handlers in `backend/src/app.py` - Registry and compatibility notes in `docs/protocols/common/http-error-codes.md` Practical rule: - For business branches, return stable `UPPER_SNAKE_CASE` codes and keep `detail` human-readable. --- ## Anti-patterns / Forbidden Patterns - Do not return free-text-only errors for business branches (missing `code`). - Protocol source: `docs/protocols/common/http-error-codes.md` - Do not swallow exceptions with `except ...: log; return default` in new code. - Project-wide rule from root `AGENTS.md`: no error swallowing. - Do not add new service/repository branches that raise `HTTPException` directly. - Backend target rule in `backend/AGENTS.md` prefers `ApiProblemError` in non-router layers. Existing legacy evidence to be aware of: - `backend/src/core/db/base_service.py` still raises `HTTPException(401, "Unauthorized")`. - `backend/src/v1/users/dependencies.py` has fallback branches returning `None` after catching exceptions in `_verify_user_with_supabase`. These are current-state observations, not patterns to copy for new code. --- ## Uncertainties (documented, not invented) - `backend/src/core/logging/middleware.py` defines `register_exception_handlers(...)` returning `{ "detail": "Internal Server Error" }` JSON (non-problem+json); main app currently defines its own handlers in `backend/src/app.py`. The single enforced runtime path should be clarified before broad refactors. - There is no automated CI check in this repo yet that verifies every endpoint always includes `code` in all error branches; compliance is currently convention + review driven.