ADR-003: RealWorld Error Contract via toJSON()
Status: Accepted
Date: 2026-04-17
Context
RealWorld spec mandates { "errors": { "<field>": ["message"] } } for all error responses. The field key varies by error type (token, credentials, article, comment, username, email, body, etc.). This cannot be a single generic handler.
Decision
Each error class owns its toJSON() shape. Error classes accept a resource or fieldErrors parameter to control the key:
AuthenticationError(message, resource='token')→{ errors: { [resource]: [message] } }AuthorizationError(message, resource='article')→{ errors: { [resource]: ['forbidden'] } }NotFoundError(resource)→{ errors: { [resource.toLowerCase()]: ['not found'] } }ConflictError(fieldErrors)→{ errors: fieldErrors }(409)ValidationError(fieldErrors)→{ errors: fieldErrors }(422, Zod field map)
Consequences
- Adding a new error type requires choosing the right class and passing the correct resource name at the throw site
- Error format is tested by 1,013 harness assertions — regressions are caught immediately
zodFieldErrors(error)helper extracts Zod issue paths into the field map format