Scattering error responses through every handler guarantees inconsistency. Instead, throw typed errors in your handlers and translate them to problem+json in one place.
flowchart LR
H[Handler throws ApiError] --> M[Error middleware]
M --> P[Map to problem+json]
P --> R[Response with correct status]
Handlers throw; one place maps errors to responses
Define an error type that carries the status and problem fields, then a single handler that converts it. Anything unexpected becomes a 500 — and you never leak a stack trace to the client.