102 lines
3.8 KiB
Markdown
102 lines
3.8 KiB
Markdown
|
|
# 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.
|