# Error Handling ## Overview All server-side errors extend a common `AppError` base class that carries a machine-readable `code`, an HTTP `statusCode`, and optional structured `details`. Infrastructure errors (K8s, Git provider) are always wrapped before surfacing so internal details stay in logs, not in HTTP responses. Unexpected errors are caught by a global `handleError` hook. The `App.Error` interface in `app.d.ts` defines the shape of errors available to `+error.svelte` pages — just `code` and `message`, both safe to display. ## Error Hierarchy ``` Error (built-in) ├── AppError — base for all application errors; has code + statusCode │ ├── NotFoundError 404 NOT_FOUND │ ├── UnauthorizedError 401 UNAUTHORIZED │ ├── ForbiddenError 403 FORBIDDEN │ ├── ValidationError 400 VALIDATION_ERROR (+ per-field details) │ ├── ConflictError 409 CONFLICT │ └── InfrastructureError 502 INFRASTRUCTURE_ERROR (wraps K8s / Git provider failures) └── ConfigError — not an HTTP error; fatal startup error ``` `ValidationError` carries a `details.fields` map of field name → error message for form validation. `InfrastructureError` wraps the original error as `cause` for logging but exposes only a sanitized message to clients. `ConfigError` is thrown during server init when a required config key is absent. It is not an HTTP error — it causes the process to exit (unhandled rejection) rather than serving a degraded state. ## Error Flow ### In route load functions and actions Throw typed `AppError` subclasses for domain errors, or use SvelteKit's `error()` helper for simple cases. `handleError` in `hooks.server.ts` maps both to the client. ### In infrastructure modules Wrap all external call failures with `wrapInfraError(system, operation, cause)` before re-throwing. Never let raw fetch or Kubernetes client errors propagate to route handlers. ### In `hooks.server.ts` (`handleError`) Catches every error that escapes a load/action/endpoint: - **`AppError`** → logged at `warn`, `{ code, message }` returned to `+error.svelte` - **anything else** → logged at `error` with full stack, generic `INTERNAL_ERROR` returned to client `requestId` from `event.locals` is included in every error log entry for correlation. No internal details (stack traces, system messages, env var values) ever reach the client.