error-model-validation-architect
Design and implement consistent API validation and error-handling behavior for Kotlin plus Spring services. Use when defining error payloads, mapping framework…
npx skills add https://github.com/kotlin/kotlin-backend-agent-skills --skill error-model-validation-architectError Model Validation Architect
Source mapping: Tier 2 high-value skill derived from Kotlin_Spring_Developer_Pipeline.md (SK-07).
Mission
Turn ad-hoc exception handling into a deliberate public contract. Treat validation and error mapping as part of API design, not a post-processing afterthought.
Inputs To Read
- Endpoint contracts and sample payloads.
- Existing exception classes and error payloads.
- Validation annotations, custom validators, and business rule failures.
- Current
@ControllerAdvice, security exception handling, and framework defaults. - Logging and observability conventions, especially correlation ids and PII policy.
Design The Error Taxonomy
Separate at least these categories:
- malformed request or unreadable JSON
- transport-level validation failure
- not found
- conflict or concurrency failure
- business rule rejection
- authentication and authorization failure
- downstream dependency failure
- unexpected internal failure
Do not collapse all non-success outcomes into one generic error envelope.
Status Code Rules
- Use
400for malformed input, type mismatch, or invalid transport shape. - Use
401for authentication failure and403for authorization failure. - Use
404when the addressed resource is absent. - Use
409for state conflicts, optimistic locking failures, duplicate idempotency keys, and uniqueness races when conflict semantics matter. - Use
422when the payload is structurally valid but violates business rules. - Use
429,502,503, or504deliberately when gateway or dependency behavior is part of the contract. - Reserve
500for genuinely unexpected internal failures.
Advanced Contract Decisions
- Separate machine-readable error code from human-readable message. Clients should not parse prose.
- Decide whether field-level validation errors should be aggregated or first-failure only. Make the rule consistent.
- Preserve nested field paths for complex payloads and collections.
- Decide whether localization is a server concern, client concern, or documentation-only concern.
- Standardize correlation or trace identifiers in the error payload only if the platform can produce them consistently.
- Decide how unknown fields, enum mismatches, and unreadable date formats surface. These are common client-integration pain points.
- Map downstream failures carefully. Not every remote
500should become your own500. - If using RFC 7807 Problem Details, decide which extensions are stable parts of the contract and which are internal.
Validation Rules
- Keep transport validation separate from domain validation even if both ultimately reject the request.
- Use Kotlin
@field:targets for Bean Validation annotations on DTO constructor properties. - Prefer dedicated validators or domain rules over abusing regex annotations for business semantics.
- Validate required configuration or invariants at startup when they are not truly request-scoped.
Framework Exception Coverage
- Cover
MethodArgumentNotValidException,ConstraintViolationException,HttpMessageNotReadableException,MethodArgumentTypeMismatchException, missing-parameter exceptions, and unsupported media-type cases explicitly if the API claims a stable error contract. - Decide how security exceptions participate in the shared error model.
AuthenticationEntryPointandAccessDeniedHandleroften need explicit alignment with controller advice. - Decide how async, scheduled, and messaging failures are reported differently from HTTP failures. One global envelope does not fit every boundary.
- If the platform uses Problem Details, verify framework-generated problem payloads do not diverge from custom ones during upgrades.
Expert Heuristics
- Let validation errors help the client recover, but let internal logs help operators diagnose. These are different audiences and should not share the same detail level.
- If the service is public, keep error-code taxonomy versionable and stable even when internal exception types change.
- When multiple validation layers reject the same request, choose the most user-actionable signal instead of stacking redundant errors.
- If a downstream dependency failure is part of the business path, decide whether the contract should expose dependency semantics or normalize them to your own domain.
Output Contract
Return these sections:
Error taxonomy: the categories and stable codes.Status mapping: which exception or failure type maps to which status and why.Payload shape: the fields that belong in every error.Framework coverage: which framework exceptions must be handled explicitly.Minimal implementation plan: advice class, exception types, and tests to add.Logging rule: what to log server-side versus what to expose to clients.
Guardrails
- Do not leak stack traces, SQL fragments, class names, tokens, or secrets to clients.
- Do not use one generic message for all failures if clients need actionable categories.
- Do not map every domain failure to
400. - Do not let security exceptions bypass the common contract unintentionally.
- Do not rely on the framework default error shape if the service claims to have a stable API contract.
Quality Bar
A good run of this skill gives clients a predictable error language and gives operators enough server-side detail to debug safely. A bad run produces a pretty error JSON that still conflates malformed input, business rejection, and internal failure.