--- description: Cross-cutting error handling rules for services, API, and UI. applyTo: 'src/transcription/**/*.py' --- # Error Handling (Cross-cutting) Primary references: - `docs/error_handling.md` - `docs/invariant/error_handling.md` - `docs/requirements.md` ## Taxonomy and Categories Use category-driven semantics aligned to canonical policy: - `validation` - `not_found` - `conflict` - `external` - `timeout` - `internal` Do not invent ad hoc categories in user/API-facing envelopes unless canonical docs are updated. Runtime/internal categories may be more specific for diagnostics and persistence, but they must map deterministically to the canonical envelope categories through the centralized mapper in `transcription.errors.canonical_error_category`. Current internal categories: - `validation_error` - `user_input_error` - `not_found_error` - `conflict_error` - `external_provider_error` - `external_timeout_error` - `processing_error` - `infrastructure_transient_error` - `infrastructure_persistent_error` - `internal_unexpected_error` Required internal -> canonical mapping: - `validation_error`, `user_input_error` -> `validation` - `not_found_error` -> `not_found` - `conflict_error` -> `conflict` - `external_provider_error` -> `external` - `external_timeout_error`, `infrastructure_transient_error` -> `timeout` - `processing_error`, `infrastructure_persistent_error`, `internal_unexpected_error` -> `internal` ## Translation Boundaries - **Provider/adapters:** raise provider/domain exceptions; do not emit UI text. - **Services:** map raw exceptions into internal categories and preserve causal chain (`raise ... from ...`). - **UI/API:** map internal category -> canonical envelope category and emit user-safe, actionable messages. ## Retry Rules - No auto-retry for `validation`, `not_found`, `conflict`. - `external`/`timeout` may be retried when operation semantics are safe. - Preserve each retry as new evidence where applicable (no history rewrite). ## Job/Page Failure Semantics - Page-level (`JobSource`): `pending`, `transcribed`, `failed`, `cancelled`. - Job terminals: `transcribed`, `partial_success`, `failed`. - Cancellation must keep job-level and page-level semantics explicit and consistent. - Do not emit legacy terminal state language such as `completed` in active user/API lifecycle contracts. ## User-Safe Messaging - Never leak stack traces, credentials, auth headers, or local filesystem paths in user-facing output. - Include actionable remediation guidance aligned to category. - Keep envelope structure consistent across API endpoints. ### `AppError.message` vs `AppError.detail` `AppError` carries two texts with different audiences, and they must not be collapsed. Getting this wrong has already caused a real defect in this repository, in both directions. | Attribute | Audience | Reaches | Rule | | :--- | :--- | :--- | :--- | | `message` | User and API clients | `ErrorEnvelope.message`, UI notifications | Stays generic. Never embed exception text, provider payloads, or filesystem paths. | | `detail` | Internal only | Logs, and `format_error_detail` -> `ExecutionAttempt.error_detail` and `MaintenanceRun.error_detail` | Carries the root cause. Never rendered to users or serialized into an envelope. | - Putting root-cause data in `message` leaks infrastructure detail to users. - Omitting it from `detail` silently degrades the provenance record this system exists to preserve — a failed attempt whose `error_detail` says nothing is an attempt that cannot be diagnosed later. - When you raise from a caught exception, populate **both**: a generic `message` and a `detail` carrying `type(exc).__name__` and the exception text, with `raise ... from exc`. - `detail` is optional (`None`). A read path that assumes it is populated must handle its absence. - Before changing either attribute, or any helper that formats them, enumerate every consumer — evidence writes, maintenance runs, logging, API envelopes, and UI presentation all read these fields, and tests assert on the persisted text. Canonical definitions live in `src/transcription/errors.py`; see also `docs/error_handling.md`. ## Logging and Diagnostics - Log operation identifiers and error IDs where available. - Preserve category + cause-chain context. - Distinguish no-response timeout/network failures from returned provider error responses. ## Guardrails - No broad catch-and-swallow patterns. - No success-shaped fallback values after exceptions. - Category mapping must remain deterministic and testable. ## Contract Sync Rule If taxonomy, retries, or envelope semantics change: 1. Update canonical docs (`docs/error_handling.md`, and invariant docs if needed). 2. Update tests in the same change. 3. Update related instruction/skill references. 4. If change affects persisted status/category fields, update `docs/schema.md` when applicable.